大部分
This commit is contained in:
parent
2bbccd9a5f
commit
8f92dc3ed3
|
@ -4,6 +4,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="//unpkg.com/@element-plus/icons-vue"></script>
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
"name": "zt-sys",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"axios": "^1.7.2",
|
||||
"element-plus": "^2.7.7",
|
||||
"pinia": "^2.1.7",
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"axios": "^1.7.2",
|
||||
"element-plus": "^2.7.7",
|
||||
"pinia": "^2.1.7",
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import http from "@/utils/http";
|
||||
//获取题目
|
||||
export const getQuestion= (type)=>{
|
||||
if(type==null||type==undefined){
|
||||
type="refresh";
|
||||
}
|
||||
return http({
|
||||
url:"/question/getQuestion",
|
||||
method:"get",
|
||||
params:{
|
||||
type
|
||||
},
|
||||
})
|
||||
}
|
||||
//注册
|
||||
export const validationAnswer= (user)=>{
|
||||
return http({
|
||||
url:"/question/validationAnswer",
|
||||
method:"get",
|
||||
data:user,
|
||||
headers:{
|
||||
isToken:false
|
||||
}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
import http from "@/utils/http";
|
||||
//登录
|
||||
export const login= (user)=>{
|
||||
return http({
|
||||
url:"/user/login",
|
||||
method:"post",
|
||||
data:user,
|
||||
headers:{
|
||||
isToken:false
|
||||
}
|
||||
})
|
||||
}
|
||||
//注册
|
||||
export const register= (user)=>{
|
||||
return http({
|
||||
url:"/user/register",
|
||||
method:"post",
|
||||
data:user,
|
||||
headers:{
|
||||
isToken:false
|
||||
}
|
||||
})
|
||||
}
|
||||
//获取用户信息
|
||||
export const getUserInfo= ()=>{
|
||||
return http({
|
||||
url:"/user",
|
||||
method:"get"
|
||||
})
|
||||
}
|
||||
//修改用户信息
|
||||
export const updateUserInfo= (user)=>{
|
||||
return http.request({
|
||||
url:"/user/update",
|
||||
method:"post",
|
||||
params:user
|
||||
})
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
Binary file not shown.
After Width: | Height: | Size: 295 KiB |
|
@ -1,44 +0,0 @@
|
|||
<script setup>
|
||||
defineProps({
|
||||
msg: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="greetings">
|
||||
<h1 class="green">{{ msg }}</h1>
|
||||
<h3>
|
||||
You’ve successfully created a project with
|
||||
<a href="https://vitejs.dev/" target="_blank" rel="noopener">Vite</a> +
|
||||
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>.
|
||||
</h3>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
h1 {
|
||||
font-weight: 500;
|
||||
font-size: 2.6rem;
|
||||
position: relative;
|
||||
top: -10px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.greetings h1,
|
||||
.greetings h3 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.greetings h1,
|
||||
.greetings h3 {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,88 +0,0 @@
|
|||
<script setup>
|
||||
import WelcomeItem from './WelcomeItem.vue'
|
||||
import DocumentationIcon from './icons/IconDocumentation.vue'
|
||||
import ToolingIcon from './icons/IconTooling.vue'
|
||||
import EcosystemIcon from './icons/IconEcosystem.vue'
|
||||
import CommunityIcon from './icons/IconCommunity.vue'
|
||||
import SupportIcon from './icons/IconSupport.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<DocumentationIcon />
|
||||
</template>
|
||||
<template #heading>Documentation</template>
|
||||
|
||||
Vue’s
|
||||
<a href="https://vuejs.org/" target="_blank" rel="noopener">official documentation</a>
|
||||
provides you with all information you need to get started.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<ToolingIcon />
|
||||
</template>
|
||||
<template #heading>Tooling</template>
|
||||
|
||||
This project is served and bundled with
|
||||
<a href="https://vitejs.dev/guide/features.html" target="_blank" rel="noopener">Vite</a>. The
|
||||
recommended IDE setup is
|
||||
<a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a> +
|
||||
<a href="https://github.com/johnsoncodehk/volar" target="_blank" rel="noopener">Volar</a>. If
|
||||
you need to test your components and web pages, check out
|
||||
<a href="https://www.cypress.io/" target="_blank" rel="noopener">Cypress</a> and
|
||||
<a href="https://on.cypress.io/component" target="_blank" rel="noopener"
|
||||
>Cypress Component Testing</a
|
||||
>.
|
||||
|
||||
<br />
|
||||
|
||||
More instructions are available in <code>README.md</code>.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<EcosystemIcon />
|
||||
</template>
|
||||
<template #heading>Ecosystem</template>
|
||||
|
||||
Get official tools and libraries for your project:
|
||||
<a href="https://pinia.vuejs.org/" target="_blank" rel="noopener">Pinia</a>,
|
||||
<a href="https://router.vuejs.org/" target="_blank" rel="noopener">Vue Router</a>,
|
||||
<a href="https://test-utils.vuejs.org/" target="_blank" rel="noopener">Vue Test Utils</a>, and
|
||||
<a href="https://github.com/vuejs/devtools" target="_blank" rel="noopener">Vue Dev Tools</a>. If
|
||||
you need more resources, we suggest paying
|
||||
<a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">Awesome Vue</a>
|
||||
a visit.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<CommunityIcon />
|
||||
</template>
|
||||
<template #heading>Community</template>
|
||||
|
||||
Got stuck? Ask your question on
|
||||
<a href="https://chat.vuejs.org" target="_blank" rel="noopener">Vue Land</a>, our official
|
||||
Discord server, or
|
||||
<a href="https://stackoverflow.com/questions/tagged/vue.js" target="_blank" rel="noopener"
|
||||
>StackOverflow</a
|
||||
>. You should also subscribe to
|
||||
<a href="https://news.vuejs.org" target="_blank" rel="noopener">our mailing list</a> and follow
|
||||
the official
|
||||
<a href="https://twitter.com/vuejs" target="_blank" rel="noopener">@vuejs</a>
|
||||
twitter account for latest news in the Vue world.
|
||||
</WelcomeItem>
|
||||
|
||||
<WelcomeItem>
|
||||
<template #icon>
|
||||
<SupportIcon />
|
||||
</template>
|
||||
<template #heading>Support Vue</template>
|
||||
|
||||
As an independent project, Vue relies on community backing for its sustainability. You can help
|
||||
us by
|
||||
<a href="https://vuejs.org/sponsor/" target="_blank" rel="noopener">becoming a sponsor</a>.
|
||||
</WelcomeItem>
|
||||
</template>
|
|
@ -0,0 +1,63 @@
|
|||
<template>
|
||||
<div class="topicInfoBox">
|
||||
<div class="flex gap-2" style="width: 90%; margin: 0 auto">
|
||||
<el-tag v-for="itme in props.tags" :key="itme.name" type="primary">{{ itme.name}}</el-tag>
|
||||
</div>
|
||||
<div class="introduce">
|
||||
{{ props.introduce }}
|
||||
</div>
|
||||
<p style="width: 90%; margin: 0 auto">
|
||||
{{ props.topicTitle }}
|
||||
</p>
|
||||
<div class="introduce">
|
||||
<el-radio-group v-model="radio">
|
||||
<el-radio
|
||||
v-for="itme in topicSelect"
|
||||
:key="itme.key"
|
||||
:value="itme.key"
|
||||
>{{ itme.key + "." + itme.name }}</el-radio
|
||||
>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div class="introduce">
|
||||
<el-button v-if="radio != null" type="success">提交</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.topicInfoBox {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.introduce {
|
||||
margin: 10px auto;
|
||||
width: 90%;
|
||||
word-break: normal;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
</style>
|
||||
<script setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
const props = defineProps({
|
||||
id: { type: Number, default: null },
|
||||
videoUrl: { type: String, default: null },
|
||||
topicList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
type: { type: Number, default: null },
|
||||
topicTitle: { type: String, default: "题目" },
|
||||
introduce: { type: String, default: "介绍" },
|
||||
tags: { type: Array, default: null },
|
||||
});
|
||||
const topicSelect = ref([]);
|
||||
onMounted(() => {
|
||||
topicSelect.value = props.topicList;
|
||||
});
|
||||
const radio = ref(null);
|
||||
</script>
|
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<div class="word-list">
|
||||
<div
|
||||
v-for="word in words"
|
||||
:key="word"
|
||||
class="word-item"
|
||||
@click="handleWordClick(word)"
|
||||
>
|
||||
{{ word }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
const emit=defineEmits(['select'])
|
||||
// 包含所有可点击词的数组
|
||||
const words = ref([
|
||||
'高数上', '高数下', '线性代数', '数学分析', '解析几何',
|
||||
'概率论与数理统计', '复变函数', '实变函数', '常微分方程',
|
||||
'近世代数', '数据结构', 'C语言', '软件工程类', '大学物理(简明)',
|
||||
'物理实验', '力学', '热学', '光学', '电磁学', '原子物理学',
|
||||
'物理专业', '高中物理', '初中物理', '高中化学', '初中化学',
|
||||
'高中数学', '初中数学', '小学数学', '高中生物', '初中生物',
|
||||
'有机化学', '无机化学', '分析化学', '物理化学', '结构化学',
|
||||
'高分子化学', '配位化学', '生物化学', '普通生物学', '细胞生物学',
|
||||
'遗传学', '微生物学', '植物学', '动物学', '数学', '物理', '化学', '生物',
|
||||
'法学', '经济学', '其他'
|
||||
]);
|
||||
const handleWordClick = (word) => {
|
||||
console.log(`Clicked word: ${word}`);
|
||||
emit('select',word);
|
||||
// 这里可以抛出一个事件,或者调用其他方法
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.word-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
/* gap: 10px; */
|
||||
}
|
||||
.word-item {
|
||||
padding: 8px;
|
||||
border-bottom: 1px solid #43CF7C;
|
||||
cursor: pointer;
|
||||
user-select: none; /* 防止用户选择文本 */
|
||||
}
|
||||
.word-item:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,62 @@
|
|||
<template>
|
||||
<div class="video-container">
|
||||
<video
|
||||
ref="videoRef"
|
||||
:src="props.src"
|
||||
width="100%"
|
||||
height="400px"
|
||||
controls
|
||||
@play="handlePlay"
|
||||
@fullscreenchange="handleFullscreenChange"
|
||||
>
|
||||
您的浏览器不支持 video 标签。
|
||||
</video>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, onMounted, onUnmounted } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
src: String
|
||||
});
|
||||
|
||||
const videoSrc = ref(props.src);
|
||||
const videoRef = ref(null);
|
||||
const isFullscreen = ref(false);
|
||||
|
||||
const handlePlay = () => {
|
||||
console.log('视频开始播放');
|
||||
};
|
||||
|
||||
const handleFullscreenChange = () => {
|
||||
isFullscreen.value = document.fullscreenElement === videoRef.value;
|
||||
};
|
||||
watch(() => props.src, (newSrc) => {
|
||||
videoSrc.value = newSrc;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
console.log('视频组件挂载完成');
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
console.log('视频组件卸载');
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.video-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 640px; /* 可以根据需要调整 */
|
||||
/* margin: 0 auto; */
|
||||
}
|
||||
|
||||
button {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
z-index: 10;
|
||||
}
|
||||
</style>
|
|
@ -1,86 +0,0 @@
|
|||
<template>
|
||||
<div class="item">
|
||||
<i>
|
||||
<slot name="icon"></slot>
|
||||
</i>
|
||||
<div class="details">
|
||||
<h3>
|
||||
<slot name="heading"></slot>
|
||||
</h3>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.item {
|
||||
margin-top: 2rem;
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.details {
|
||||
flex: 1;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
i {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
place-content: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 500;
|
||||
margin-bottom: 0.4rem;
|
||||
color: var(--color-heading);
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.item {
|
||||
margin-top: 0;
|
||||
padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
|
||||
}
|
||||
|
||||
i {
|
||||
top: calc(50% - 25px);
|
||||
left: -26px;
|
||||
position: absolute;
|
||||
border: 1px solid var(--color-border);
|
||||
background: var(--color-background);
|
||||
border-radius: 8px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.item:before {
|
||||
content: ' ';
|
||||
border-left: 1px solid var(--color-border);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: calc(50% + 25px);
|
||||
height: calc(50% - 25px);
|
||||
}
|
||||
|
||||
.item:after {
|
||||
content: ' ';
|
||||
border-left: 1px solid var(--color-border);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: calc(50% + 25px);
|
||||
height: calc(50% - 25px);
|
||||
}
|
||||
|
||||
.item:first-of-type:before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.item:last-of-type:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,7 +0,0 @@
|
|||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
|
||||
<path
|
||||
d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
|
@ -1,7 +0,0 @@
|
|||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
|
||||
<path
|
||||
d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
|
@ -1,7 +0,0 @@
|
|||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
|
||||
<path
|
||||
d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
|
@ -1,7 +0,0 @@
|
|||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
|
||||
<path
|
||||
d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
|
@ -1,19 +0,0 @@
|
|||
<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
|
||||
<template>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
class="iconify iconify--mdi"
|
||||
width="24"
|
||||
height="24"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
</template>
|
|
@ -6,11 +6,16 @@ import ElementPlus from 'element-plus'
|
|||
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
// 如果您正在使用CDN引入,请删除下面一行。
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(createPinia())
|
||||
app.use(router)
|
||||
app.use(ElementPlus, { size: 'small', zIndex: 3000 })
|
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||
app.component(key, component)
|
||||
}
|
||||
|
||||
app.mount('#app')
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
const storage ={
|
||||
setStorage:function(key,value){
|
||||
window.localStorage.setItem(key,JSON.stringify(value))
|
||||
},
|
||||
getStorage:function(key){
|
||||
return JSON.parse(window.localStorage.getItem(key))
|
||||
},
|
||||
removeStorage:function(key){
|
||||
window.localStorage.removeItem(key)
|
||||
}
|
||||
}
|
||||
export default storage
|
|
@ -0,0 +1,35 @@
|
|||
import axios from 'axios'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import 'element-plus/theme-chalk/el-message.css'
|
||||
import TokenService from '@/utils/token'
|
||||
import router from '@/router'
|
||||
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
|
||||
const httpInstance=axios.create({
|
||||
baseURL: import.meta.env.VITE_APP_BASE_API,
|
||||
timeout: 10000
|
||||
})
|
||||
// axios请求拦截器
|
||||
httpInstance.interceptors.request.use(config => {
|
||||
// 是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
if (TokenService.hasToken() && !isToken) {
|
||||
config.headers['Authorization'] = TokenService.getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return config
|
||||
}, e => Promise.reject(e))
|
||||
|
||||
// axios响应式拦截器
|
||||
httpInstance.interceptors.response.use(res => {
|
||||
if (res.data.code === 401){
|
||||
router.push('/login')
|
||||
}
|
||||
if(res.data.code==0){
|
||||
ElMessage.error(res.data.msg)
|
||||
}
|
||||
return res.data
|
||||
}, e => {
|
||||
return Promise.reject(e)
|
||||
})
|
||||
// let abb=1;
|
||||
export default httpInstance;
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
import axios from 'axios'
|
||||
import { ElNotification , ElMessageBox, ElMessage, ElLoading } from 'element-plus'
|
||||
import 'element-plus/theme-chalk/el-message.css'
|
||||
import 'element-plus/theme-chalk/el-message-box.css'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import errorCode from '@/utils/errorCode'
|
||||
import { tansParams, blobValidate } from '@/utils/ruoyi'
|
||||
import cache from '@/plugins/cache'
|
||||
import { saveAs } from 'file-saver'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
|
||||
let downloadLoadingInstance;
|
||||
// 是否显示重新登录
|
||||
export let isRelogin = { show: false };
|
||||
|
||||
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
|
||||
// 创建axios实例
|
||||
const service = axios.create({
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL: import.meta.env.VITE_APP_BASE_API,
|
||||
// 超时
|
||||
timeout: 10000
|
||||
})
|
||||
|
||||
// request拦截器
|
||||
service.interceptors.request.use(config => {
|
||||
// 是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
// 是否需要防止数据重复提交
|
||||
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
|
||||
if (getToken() && !isToken) {
|
||||
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
// get请求映射params参数
|
||||
if (config.method === 'get' && config.params) {
|
||||
let url = config.url + '?' + tansParams(config.params);
|
||||
url = url.slice(0, -1);
|
||||
config.params = {};
|
||||
config.url = url;
|
||||
}
|
||||
if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
|
||||
const requestObj = {
|
||||
url: config.url,
|
||||
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
|
||||
time: new Date().getTime()
|
||||
}
|
||||
const requestSize = Object.keys(JSON.stringify(requestObj)).length; // 请求数据大小
|
||||
const limitSize = 5 * 1024 * 1024; // 限制存放数据5M
|
||||
if (requestSize >= limitSize) {
|
||||
console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制,无法进行防重复提交验证。')
|
||||
return config;
|
||||
}
|
||||
const sessionObj = cache.session.getJSON('sessionObj')
|
||||
if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
|
||||
cache.session.setJSON('sessionObj', requestObj)
|
||||
} else {
|
||||
const s_url = sessionObj.url; // 请求地址
|
||||
const s_data = sessionObj.data; // 请求数据
|
||||
const s_time = sessionObj.time; // 请求时间
|
||||
const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交
|
||||
if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
|
||||
const message = '数据正在处理,请勿重复提交';
|
||||
console.warn(`[${s_url}]: ` + message)
|
||||
return Promise.reject(new Error(message))
|
||||
} else {
|
||||
cache.session.setJSON('sessionObj', requestObj)
|
||||
}
|
||||
}
|
||||
}
|
||||
return config
|
||||
}, error => {
|
||||
console.log(error)
|
||||
Promise.reject(error)
|
||||
})
|
||||
|
||||
// 响应拦截器
|
||||
service.interceptors.response.use(res => {
|
||||
// 未设置状态码则默认成功状态
|
||||
const code = res.data.code || 200;
|
||||
// 获取错误信息
|
||||
const msg = errorCode[code] || res.data.msg || errorCode['default']
|
||||
// 二进制数据则直接返回
|
||||
if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
|
||||
return res.data
|
||||
}
|
||||
if (code === 401) {
|
||||
if (!isRelogin.show) {
|
||||
isRelogin.show = true;
|
||||
ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
|
||||
isRelogin.show = false;
|
||||
useUserStore().logOut().then(() => {
|
||||
location.href = '/index';
|
||||
})
|
||||
}).catch(() => {
|
||||
isRelogin.show = false;
|
||||
});
|
||||
}
|
||||
return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
|
||||
} else if (code === 500) {
|
||||
ElMessage({ message: msg, type: 'error' })
|
||||
return Promise.reject(new Error(msg))
|
||||
} else if (code === 601) {
|
||||
ElMessage({ message: msg, type: 'warning' })
|
||||
return Promise.reject(new Error(msg))
|
||||
} else if (code !== 200) {
|
||||
ElNotification.error({ title: msg })
|
||||
return Promise.reject('error')
|
||||
} else {
|
||||
return Promise.resolve(res.data)
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
message = "后端接口连接异常";
|
||||
} else if (message.includes("timeout")) {
|
||||
message = "系统接口请求超时";
|
||||
} else if (message.includes("Request failed with status code")) {
|
||||
message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
}
|
||||
ElMessage({ message: message, type: 'error', duration: 5 * 1000 })
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 通用下载方法
|
||||
export function download(url, params, filename, config) {
|
||||
downloadLoadingInstance = ElLoading.service({ text: "正在下载数据,请稍候", background: "rgba(0, 0, 0, 0.7)", })
|
||||
return service.post(url, params, {
|
||||
transformRequest: [(params) => { return tansParams(params) }],
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
responseType: 'blob',
|
||||
...config
|
||||
}).then(async (data) => {
|
||||
const isBlob = blobValidate(data);
|
||||
if (isBlob) {
|
||||
const blob = new Blob([data])
|
||||
saveAs(blob, filename)
|
||||
} else {
|
||||
const resText = await data.text();
|
||||
const rspObj = JSON.parse(resText);
|
||||
const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
|
||||
ElMessage.error(errMsg);
|
||||
}
|
||||
downloadLoadingInstance.close();
|
||||
}).catch((r) => {
|
||||
console.error(r)
|
||||
ElMessage.error('下载文件出现错误,请联系管理员!')
|
||||
downloadLoadingInstance.close();
|
||||
})
|
||||
}
|
||||
|
||||
export default service
|
|
@ -1,8 +1,309 @@
|
|||
<template>
|
||||
<div>首页</div>
|
||||
</template>
|
||||
<div class="homeBox">
|
||||
<div class="nav">
|
||||
<div><span class="loogText">Xuaua</span></div>
|
||||
<div>
|
||||
<el-popover :width="700" trigger="click">
|
||||
<template #reference>
|
||||
<div class="selectInput">
|
||||
<div @click="selectClick">
|
||||
<el-icon :size="size" :color="color">
|
||||
<Search />
|
||||
</el-icon>
|
||||
</div>
|
||||
<input type="text" placeholder="搜索关键词" v-model="selectType" />
|
||||
</div>
|
||||
</template>
|
||||
<TypeSelect @select="selectInput"></TypeSelect>
|
||||
</el-popover>
|
||||
</div>
|
||||
<div @click="router.push('/user')">
|
||||
<el-avatar :size="40" :src="circleUrl" />用户名
|
||||
</div>
|
||||
</div>
|
||||
<div class="main">
|
||||
<div class="mainBox">
|
||||
<div class="topicInfo" ref="topicInfoRef" @click="huadong">
|
||||
<div
|
||||
ref="topicInfoItemRef"
|
||||
style="
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
transition: 0.7s;
|
||||
"
|
||||
>
|
||||
<div
|
||||
v-for="itme in topicInfo.topicList"
|
||||
:key="itme.id"
|
||||
class="topicInfoItem"
|
||||
>
|
||||
<TopicBox
|
||||
:id="itme.id"
|
||||
:videoUrl="itme.videoUrl"
|
||||
:introduce="itme.introduce"
|
||||
:tags="itme.tags"
|
||||
:topicTitle="itme.topicTitle"
|
||||
:type="itme.type"
|
||||
:topicList="itme.xuauaQuestionAnswerList"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="topicAnswer">
|
||||
<div class="SelectAnswer">
|
||||
<div @click="get">视频</div>
|
||||
<div>解析</div>
|
||||
<div>
|
||||
<el-icon :size="27" :color="color">
|
||||
<Star />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="answerInfo">
|
||||
<VideoBox
|
||||
:src="topicInfo.topicList[topicInfo.index - 1].videoUrl"
|
||||
></VideoBox>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.homeBox {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.nav {
|
||||
width: 100%;
|
||||
height: 8vh;
|
||||
background-color: #fff;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<script setup>
|
||||
</script>
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.loogText {
|
||||
font-size: 30px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
.main {
|
||||
width: 100%;
|
||||
//占满的剩余空间
|
||||
flex: 1;
|
||||
background-color: #ededed;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.mainBox {
|
||||
width: 97%;
|
||||
height: 97%;
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
.topicInfo {
|
||||
// animation-duration: 2s;
|
||||
// animation-delay: 250ms;
|
||||
width: 30%;
|
||||
height: 100%;
|
||||
// background-color: #f0f9cc;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background-image: url("@/assets/image/tibg.jpg");
|
||||
background-size: cover; // 背景图片铺满元
|
||||
// background-position: center; // 背景图片居中显示
|
||||
background-repeat: no-repeat; // 背景图片不重复
|
||||
background-position: left left;
|
||||
.topicInfoItem {
|
||||
// top: -10px;
|
||||
// animation-duration: 2s;
|
||||
// animation-delay: 250ms;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
box-sizing: content-box;
|
||||
// border: 1px solid red;
|
||||
}
|
||||
}
|
||||
.topicAnswer {
|
||||
width: 69%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
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 {
|
||||
width: 100%;
|
||||
height: 92%;
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
// background-color: #f0f9cc;
|
||||
background-image: url("@/assets/image/tibg.jpg");
|
||||
background-size: cover; // 背景图片铺满元
|
||||
background-position: center; // 背景图片居中显示
|
||||
background-repeat: no-repeat; // 背景图片不重复
|
||||
}
|
||||
// background-color: #F0F9CC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.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%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script setup>
|
||||
import { reactive, ref, onMounted } from "vue";
|
||||
import TopicBox from "@/components/TopicBox.vue";
|
||||
import VideoBox from "@/components/VideoBox.vue";
|
||||
import TypeSelect from '@/components/TypeSelect.vue'
|
||||
import { ElMessage } from "element-plus";
|
||||
import "element-plus/theme-chalk/el-message.css";
|
||||
import router from "@/router";
|
||||
import { getQuestion } from "@/api/question/question";
|
||||
// import { c } from "vite/dist/node/types.d-aGj9QkWt";
|
||||
const topicInfoItemRef = ref(null);
|
||||
const selectType=ref(null);
|
||||
const topicInfo = reactive({
|
||||
index: 1,
|
||||
number: 3,
|
||||
topicList: [{ id: 1 }, { id: 2 }, { id: 3 }],
|
||||
});
|
||||
let mouseDown = false;
|
||||
const selectInput=(word)=>{
|
||||
selectType.value=word;
|
||||
}
|
||||
const selectClick=async()=>{
|
||||
let res = await getQuestionInfo(selectType.value);
|
||||
topicInfo.index=1;
|
||||
topicInfo.topicList = res;
|
||||
topicInfo.number = res.length;
|
||||
}
|
||||
// 鼠标按下时的位
|
||||
let lastY = null;
|
||||
//实时鼠标位
|
||||
let currentY = null;
|
||||
// 鼠标按下时触发的事件
|
||||
const huadong = () => {};
|
||||
document.addEventListener("mousedown", function (event) {
|
||||
mouseDown = true;
|
||||
// lastX = event.clientX;
|
||||
lastY = event.clientY;
|
||||
// currentX = event.clientX;
|
||||
currentY = event.clientY;
|
||||
// console.log("鼠标按下位置:", lastX, lastY);
|
||||
|
||||
// 开始实时监听鼠标移动
|
||||
document.addEventListener("mousemove", onMouseMove);
|
||||
});
|
||||
// 鼠标移动时触发的事件
|
||||
function onMouseMove(event) {
|
||||
if (mouseDown) {
|
||||
let deltaY = event.clientY - currentY;
|
||||
currentY = event.clientY;
|
||||
setScrollY(deltaY);
|
||||
}
|
||||
}
|
||||
// 鼠标松开时触发的事件
|
||||
document.addEventListener("mouseup", function (event) {
|
||||
mouseDown = false;
|
||||
let deltaY = event.clientY - lastY;
|
||||
console.log("变化", deltaY);
|
||||
flipPage(deltaY);
|
||||
document.removeEventListener("mousemove", onMouseMove);
|
||||
});
|
||||
const topicInfoRef = ref(null);
|
||||
const get = () => {
|
||||
console.log("信息", getScrollbarPosition());
|
||||
};
|
||||
const setScrollY = (y) => {
|
||||
if (topicInfoRef.value) {
|
||||
topicInfoRef.value.scrollTop = topicInfoRef.value.scrollTop - y;
|
||||
}
|
||||
};
|
||||
const flipPage = (y) => {
|
||||
if (topicInfoItemRef.value) {
|
||||
topicInfoRef.value.scrollTop = 0;
|
||||
if (y < -80) {
|
||||
topicInfo.index++;
|
||||
if (topicInfo.index > topicInfo.number) {
|
||||
topicInfo.index = topicInfo.number;
|
||||
ElMessage({ message: "没有更多了", type: "warning" });
|
||||
}
|
||||
if (topicInfo.index == topicInfo.number) {
|
||||
//最后一个了准备记载新数据
|
||||
// topicInfo.number+=3;
|
||||
// topicInfo.topicList=[...topicInfo.topicList,...[{id:topicInfo.number+1},{id:topicInfo.number+2},{id:topicInfo.number+3}
|
||||
// ]]
|
||||
}
|
||||
}
|
||||
else if (y > 80) {
|
||||
topicInfo.index--;
|
||||
if (topicInfo.index == 0) {
|
||||
topicInfo.index = 1;
|
||||
ElMessage({ message: "到顶了", type: "warning" });
|
||||
}
|
||||
}
|
||||
|
||||
// alert("123")
|
||||
topicInfoItemRef.value.style.top =
|
||||
-(topicInfo.index - 1) * topicInfoItemRef.value.clientHeight + "px";
|
||||
}
|
||||
};
|
||||
const getScrollbarPosition = () => {
|
||||
if (topicInfoRef.value) {
|
||||
const element = topicInfoRef.value;
|
||||
return {
|
||||
scrollLeft: element.scrollLeft, // 水平滚动条位置
|
||||
scrollTop: element.scrollTop, // 垂直滚动条位置
|
||||
scrollWidth: element.scrollWidth, // 元素内容的总宽度
|
||||
scrollHeight: element.scrollHeight, // 元素内容的总高度
|
||||
clientWidth: element.clientWidth, // 元素可视区域的宽度
|
||||
clientHeight: element.clientHeight, // 元素可视区域的高度
|
||||
};
|
||||
}
|
||||
return null;
|
||||
};
|
||||
const getQuestionInfo = async (type) => {
|
||||
let res = await getQuestion(type);
|
||||
console.log("res", res);
|
||||
return res.data;
|
||||
};
|
||||
onMounted(async () => {
|
||||
let res = await getQuestionInfo();
|
||||
topicInfo.index=1;
|
||||
topicInfo.topicList = res;
|
||||
topicInfo.number = res.length;
|
||||
console.log("topicInfo", topicInfo);
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<div class="inputBox">密码<input type="password" v-model="user.password" /></div>
|
||||
<div class="checkBox"><el-checkbox v-model="remember"></el-checkbox>记住密码</div>
|
||||
<div class="btnBox">
|
||||
<el-button size="large" type="success" round @click="login">登录</el-button>
|
||||
<el-button size="large" type="success" round @click="toLogin">登录</el-button>
|
||||
<el-button
|
||||
size="large"
|
||||
type="danger"
|
||||
|
@ -121,19 +121,37 @@ input:focus {
|
|||
<script setup>
|
||||
import {ElMessage} from "element-plus";
|
||||
import 'element-plus/theme-chalk/el-message.css'
|
||||
import 'element-plus/theme-chalk/el-message-box.css'
|
||||
import { ref, reactive } from "vue";
|
||||
import { login , register } from "@/api/user/user";
|
||||
import storage from '@/utils/Sotrage'
|
||||
import TokenService from '@/utils/token'
|
||||
import router from '@/router'
|
||||
import { ref, reactive,onMounted } from "vue";
|
||||
const user=reactive({
|
||||
username: "",
|
||||
password: "",
|
||||
});
|
||||
//是否记住密码
|
||||
const remember = ref(false);
|
||||
const login = () => {
|
||||
if(user.username===""||user.password===""){
|
||||
ElMessage({ message: "请输入完整信息", type: 'warning' })
|
||||
}
|
||||
const toLogin = async () => {
|
||||
console.log(user);
|
||||
if(user.username===""||user.username===null||user.password===""||user.password===null){
|
||||
ElMessage({ message: "请输入完整信息", type: 'warning' })
|
||||
}
|
||||
|
||||
let res=await login(user);
|
||||
if(res.code===200){
|
||||
ElMessage({ message: "登录成功", type: 'success' })
|
||||
if(remember.value){
|
||||
storage.setStorage("username",user.username);
|
||||
storage.setStorage("password",user.password);
|
||||
}else{
|
||||
storage.removeStorage("username");
|
||||
storage.removeStorage("password");
|
||||
}
|
||||
TokenService.saveToken(res.token)
|
||||
//跳转
|
||||
router.push('/');
|
||||
}
|
||||
};
|
||||
//表单弹窗开关
|
||||
const dialogFormVisible = ref(false);
|
||||
|
@ -146,10 +164,10 @@ const ruleForm = reactive({
|
|||
});
|
||||
//表单验证
|
||||
const usernamevalidate = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
if (value === ""||value==null) {
|
||||
callback(new Error("请输入账号"));
|
||||
callback();
|
||||
}
|
||||
callback();
|
||||
};
|
||||
const validatePass = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
|
@ -189,13 +207,25 @@ const rules = reactive({
|
|||
//提交注册
|
||||
const submitForm = (formEl) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate((valid) => {
|
||||
formEl.validate(async(valid) => {
|
||||
if (valid) {
|
||||
console.log("submit!");
|
||||
// console.log("submit!");
|
||||
let res =await register({username:ruleForm.username,password:ruleForm.password});
|
||||
if(res.code===200){
|
||||
ElMessage({ message: "注册成功", type: 'success' })
|
||||
dialogFormVisible.value=false;
|
||||
}else{
|
||||
ElMessage({ message: res.msg, type: 'error' })
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log("error submit!");
|
||||
}
|
||||
});
|
||||
};
|
||||
onMounted(() => {
|
||||
console.log("onMounted");
|
||||
user.username=storage.getStorage("username");
|
||||
user.password=storage.getStorage("password");
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,8 +1,108 @@
|
|||
<template>
|
||||
<div>用户</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<script setup>
|
||||
</script>
|
||||
<div class="userBox">
|
||||
<div class="userInfo">
|
||||
<div class="userT">
|
||||
<el-avatar :size="150" :src="circleUrl" />
|
||||
</div>
|
||||
<div class="userName">用户名</div>
|
||||
<div class="userName" @click="router.push('/');">返回首页</div>
|
||||
</div>
|
||||
<div class="collectionTopic">
|
||||
<div class="title">收藏</div>
|
||||
<div class="collectionList">
|
||||
<div class="collectionTme"></div>
|
||||
<div class="collectionTme"></div>
|
||||
<div class="collectionTme"></div>
|
||||
<div class="collectionTme"></div>
|
||||
<div class="collectionTme"></div>
|
||||
<div class="collectionTme"></div>
|
||||
<div class="collectionTme"></div>
|
||||
<div class="collectionTme"></div>
|
||||
<!-- <div class="collectionTme"></div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.userBox {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-image: url("@/assets/image/userbg.jpg");
|
||||
background-size: cover; // 背景图片铺满元素
|
||||
background-position: center; // 背景图片居中显示
|
||||
background-repeat: no-repeat; // 背景图片不重复
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.userInfo {
|
||||
height: 90%;
|
||||
width: 20%;
|
||||
// background-color: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// justify-content: space-between;
|
||||
align-items: center;
|
||||
.userName {
|
||||
margin-top: 30px;
|
||||
font-size: 30px;
|
||||
}
|
||||
.userT {
|
||||
margin-top: 90px;
|
||||
}
|
||||
}
|
||||
.collectionTopic {
|
||||
margin-left: 30px;
|
||||
width: 60%;
|
||||
height: 90%;
|
||||
// background-color: #ff0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// justify-content: space-between;
|
||||
align-items: center;
|
||||
.title {
|
||||
margin-top: 10px;
|
||||
font-size: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 90%;
|
||||
height: 5%;
|
||||
background-color: #d2fce3;
|
||||
border-radius: 70px;
|
||||
}
|
||||
.collectionList {
|
||||
overflow-y: auto;
|
||||
scrollbar-width: none; /* Firefox */
|
||||
-ms-overflow-style: none; /* IE 10+ */
|
||||
::-webkit-scrollbar {
|
||||
display: none; /* Chrome Safari */
|
||||
}
|
||||
flex: 1;
|
||||
width: 90%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
// justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
padding: 10px;
|
||||
.collectionTme {
|
||||
/* 宽度是固定好的 */
|
||||
width: 30%;
|
||||
height: 47%;
|
||||
background-color: #D2FCE3;
|
||||
margin-bottom: 10px;
|
||||
// border: 1px solid red;
|
||||
/*这个数值需要自己去调*/
|
||||
margin-right: 17px;
|
||||
}
|
||||
}
|
||||
.collectionList:after {
|
||||
content: "";
|
||||
flex: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script setup>
|
||||
import router from '@/router'
|
||||
</script>
|
||||
|
|
Loading…
Reference in New Issue