mirror of
https://github.com/shuguangnet/Code-Master.git
synced 2025-01-23 07:58:44 +08:00
优化个人中心
This commit is contained in:
parent
19f535c028
commit
1730c2f51e
@ -35,37 +35,3 @@ router.beforeEach(async (to, from, next) => {
|
||||
}
|
||||
next();
|
||||
});
|
||||
// import router from "@/router";
|
||||
// import store from "@/store";
|
||||
// import ACCESS_ENUM from "@/access/ACCESS_ENUM";
|
||||
// import checkAccess from "@/access/access_check";
|
||||
|
||||
// router.beforeEach(async (to, from, next) => {
|
||||
// console.log("登陆用户信息", store.state.user.loginUser);
|
||||
// let loginUser = store.state.user.loginUser;
|
||||
// // 如果之前没登陆过,自动登录
|
||||
// if (!loginUser || !loginUser.userRole) {
|
||||
// // 加 await 是为了等用户登录成功之后,再执行后续的代码
|
||||
// await store.dispatch("user/getLoginUser");
|
||||
// loginUser = store.state.user.loginUser;
|
||||
// }
|
||||
// const needAccess = (to.meta?.access as string) ?? ACCESS_ENUM.NOT_LOGIN;
|
||||
// // 要跳转的页面必须要登陆
|
||||
// if (needAccess !== ACCESS_ENUM.NOT_LOGIN) {
|
||||
// // 如果没登陆,跳转到登录页面
|
||||
// if (
|
||||
// // !loginUser ||
|
||||
// // !loginUser.userRole ||
|
||||
// loginUser.userRole === ACCESS_ENUM.NOT_LOGIN
|
||||
// ) {
|
||||
// next(`/user/login?redirect=${to.fullPath}`);
|
||||
// return;
|
||||
// }
|
||||
// // 如果已经登陆了,但是权限不足,那么跳转到无权限页面
|
||||
// if (!checkAccess(loginUser, needAccess)) {
|
||||
// next("/noAuth");
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// next();
|
||||
// });
|
||||
|
@ -62,7 +62,7 @@
|
||||
<!-- <p>已登录</p> -->
|
||||
</a-avatar>
|
||||
<template #content>
|
||||
<a-doption>
|
||||
<a-doption @click="gotoCenter()">
|
||||
<a-button type="text">
|
||||
<icon-user style=" font-size: 20px;" />
|
||||
个人中心
|
||||
@ -167,7 +167,10 @@ const doMenuClick = (key: string) => {
|
||||
path: key,
|
||||
});
|
||||
};
|
||||
|
||||
// 跳转到用户中心
|
||||
const gotoCenter=()=>{
|
||||
router.push('/user/center')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
78
src/components/User/UserChangePwd.vue
Normal file
78
src/components/User/UserChangePwd.vue
Normal file
@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<div class="info" style="align-items: center;">
|
||||
<a-space direction="vertical" size="large" :style="{ width: '600px' }">
|
||||
<a-form :model="form" layout="vertical">
|
||||
<a-form-item field="oldPassword" label="旧密码">
|
||||
<a-input-password
|
||||
v-model="form.oldPassword"
|
||||
placeholder="请输入旧密码"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item field="newPassword" label="新密码">
|
||||
<a-input-password
|
||||
v-model="form.newPassword"
|
||||
placeholder="请输入新密码"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item field="confirmPassword" label="确认新密码">
|
||||
<a-input-password
|
||||
v-model="form.confirmPassword"
|
||||
placeholder="请再次输入新密码"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-button type="primary" class="save" @click="savePassword">
|
||||
保存
|
||||
</a-button>
|
||||
</a-form>
|
||||
</a-space>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { UserControllerService } from '../../../generated';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
// 定义密码修改表单
|
||||
const form = ref({
|
||||
oldPassword: '',
|
||||
newPassword: '',
|
||||
confirmPassword: ''
|
||||
});
|
||||
|
||||
// 保存密码修改
|
||||
const savePassword = async () => {
|
||||
// 检查新密码和确认密码是否一致
|
||||
if (form.value.newPassword !== form.value.confirmPassword) {
|
||||
Message.error('新密码和确认密码不一致');
|
||||
return;
|
||||
}
|
||||
|
||||
const res = await UserControllerService.updatePasswordUsingPost(form.value);
|
||||
if (res.code === 0) {
|
||||
Message.success('密码修改成功');
|
||||
// 跳转到其他页面或执行其他操作
|
||||
} else {
|
||||
Message.error('密码修改失败: ' + res.message);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.info {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%; /* 使其占满父元素的高度 */
|
||||
/* background-color: #f0f2f5; 设置背景色 */
|
||||
padding: 20px; /* 内边距 */
|
||||
}
|
||||
|
||||
.save {
|
||||
margin-top: 20px; /* 按钮与表单的间距 */
|
||||
}
|
||||
</style>
|
@ -1,7 +1,9 @@
|
||||
<template>
|
||||
<div class="info">
|
||||
<div class="avatar" style="display: flex;justify-content: center;">
|
||||
<a-avatar id="userAvatar" @click="onClcik" :style="{ backgroundColor: '#0A65CC' }">
|
||||
<div class="info" style="align-items: center;">
|
||||
<div class="avatar" style="display: flex;justify-content: center;align-items: center;width: 50%;">
|
||||
|
||||
<a-avatar :size="100" id="userAvatar" @click="onClcik" :style="{ backgroundColor: '#0A65CC' }">
|
||||
|
||||
<img v-if="form.userAvatar" class="avatar-image" alt="avatar" :src="form.userAvatar" />
|
||||
<IconUser v-else />
|
||||
<template #trigger-icon>
|
||||
|
93
src/components/User/UserPost.vue
Normal file
93
src/components/User/UserPost.vue
Normal file
@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<a-list
|
||||
class="list-demo-action-layout"
|
||||
:bordered="false"
|
||||
:data="dataSource"
|
||||
:pagination-props="paginationProps"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
<a-list-item class="list-demo-item" action-layout="vertical">
|
||||
<template #actions>
|
||||
<span><icon-heart />83</span>
|
||||
<span><icon-star />{{ item.index }}</span>
|
||||
<span><icon-message />Reply</span>
|
||||
</template>
|
||||
<template #extra>
|
||||
<div className="image-area">
|
||||
<img alt="arco-design" :src="item.imageSrc" />
|
||||
</div>
|
||||
</template>
|
||||
<a-list-item-meta
|
||||
:title="item.title"
|
||||
:description="item.description"
|
||||
>
|
||||
<template #avatar>
|
||||
<a-avatar shape="square">
|
||||
<img alt="avatar" :src="item.avatar" />
|
||||
</a-avatar>
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive } from 'vue'
|
||||
|
||||
const names = ['Socrates', 'Balzac', 'Plato'];
|
||||
const avatarSrc = [
|
||||
'//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/a8c8cdb109cb051163646151a4a5083b.png~tplv-uwbnlip3yd-webp.webp',
|
||||
'//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/e278888093bef8910e829486fb45dd69.png~tplv-uwbnlip3yd-webp.webp',
|
||||
'//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/9eeb1800d9b78349b24682c3518ac4a3.png~tplv-uwbnlip3yd-webp.webp',
|
||||
];
|
||||
const imageSrc = [
|
||||
'//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/29c1f9d7d17c503c5d7bf4e538cb7c4f.png~tplv-uwbnlip3yd-webp.webp',
|
||||
'//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/04d7bc31dd67dcdf380bc3f6aa07599f.png~tplv-uwbnlip3yd-webp.webp',
|
||||
'//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/1f61854a849a076318ed527c8fca1bbf.png~tplv-uwbnlip3yd-webp.webp',
|
||||
];
|
||||
const dataSource = new Array(15).fill(null).map((_, index) => {
|
||||
return {
|
||||
index: index,
|
||||
avatar: avatarSrc[index % avatarSrc.length],
|
||||
title: names[index % names.length],
|
||||
description:
|
||||
'Beijing ByteDance Technology Co., Ltd. is an enterprise located in China. ByteDance has products such as TikTok, Toutiao, volcano video and Douyin (the Chinese version of TikTok).',
|
||||
imageSrc: imageSrc[index % imageSrc.length],
|
||||
};
|
||||
});
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
return {
|
||||
dataSource,
|
||||
paginationProps: reactive({
|
||||
defaultPageSize: 3,
|
||||
total: dataSource.length
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.list-demo-action-layout .image-area {
|
||||
width: 183px;
|
||||
height: 119px;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.list-demo-action-layout .list-demo-item {
|
||||
padding: 20px 0;
|
||||
border-bottom: 1px solid var(--color-fill-3);
|
||||
}
|
||||
|
||||
.list-demo-action-layout .image-area img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.list-demo-action-layout .arco-list-item-action .arco-icon {
|
||||
margin: 0 4px;
|
||||
}
|
||||
</style>
|
98
src/components/User/UserReview.vue
Normal file
98
src/components/User/UserReview.vue
Normal file
@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<a-comment author="Balzac" datetime="1 hour" align="right" v-for="item in 10">
|
||||
<template #actions>
|
||||
<span class="action" key="heart" @click="onLikeChange">
|
||||
<span v-if="like">
|
||||
<IconHeartFill :style="{ color: '#f53f3f' }" />
|
||||
</span>
|
||||
<span v-else>
|
||||
<IconHeart />
|
||||
</span>
|
||||
{{ 83 + (like ? 1 : 0) }}
|
||||
</span>
|
||||
<span class="action" key="star" @click="onStarChange">
|
||||
<span v-if="star">
|
||||
<IconStarFill style="{ color: '#ffb400' }" />
|
||||
</span>
|
||||
<span v-else>
|
||||
<IconStar />
|
||||
</span>
|
||||
{{ 3 + (star ? 1 : 0) }}
|
||||
</span>
|
||||
<span class="action" key="reply">
|
||||
<IconMessage /> Reply
|
||||
</span>
|
||||
</template>
|
||||
<template #avatar>
|
||||
<a-avatar>
|
||||
<img
|
||||
alt="avatar"
|
||||
src="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/3ee5f13fb09879ecb5185e440cef6eb9.png~tplv-uwbnlip3yd-webp.webp"
|
||||
/>
|
||||
</a-avatar>
|
||||
</template>
|
||||
<template #content>
|
||||
<div>
|
||||
A design is a plan or specification for the construction of an object or
|
||||
system or for the implementation of an activity or process, or the
|
||||
result of that plan or specification in the form of a prototype, product
|
||||
or process.
|
||||
</div>
|
||||
</template>
|
||||
</a-comment>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref } from 'vue';
|
||||
import {
|
||||
IconHeart,
|
||||
IconMessage,
|
||||
IconStar,
|
||||
IconStarFill,
|
||||
IconHeartFill,
|
||||
} from '@arco-design/web-vue/es/icon';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
IconHeart,
|
||||
IconMessage,
|
||||
IconStar,
|
||||
IconStarFill,
|
||||
IconHeartFill,
|
||||
},
|
||||
setup() {
|
||||
const like = ref(false);
|
||||
const star = ref(false);
|
||||
const onLikeChange = () => {
|
||||
like.value = !like.value;
|
||||
};
|
||||
const onStarChange = () => {
|
||||
star.value = !star.value;
|
||||
};
|
||||
|
||||
return {
|
||||
like,
|
||||
star,
|
||||
onLikeChange,
|
||||
onStarChange
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.action {
|
||||
display: inline-block;
|
||||
padding: 0 4px;
|
||||
color: var(--color-text-1);
|
||||
line-height: 24px;
|
||||
background: transparent;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
transition: all 0.1s ease;
|
||||
}
|
||||
|
||||
.action:hover {
|
||||
background: var(--color-fill-3);
|
||||
}
|
||||
</style>
|
@ -147,23 +147,29 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- 登录弹框 -->
|
||||
<a-modal v-model:visible="visible" @cancel="handleCancel" :footer="null" >
|
||||
<UserLoginView />
|
||||
</a-modal>
|
||||
<div v-if="visible" class="overlay" @click.self="handleCancel" >
|
||||
<div class="login-container">
|
||||
<div v-if="ModelInfo=='login'">
|
||||
<UserLoginView @goToReg ="UserModel" :ModelStatus="ModelStatus" />
|
||||
</div>
|
||||
<div v-else-if="ModelInfo=='reg'">
|
||||
<UserRegView @goToLogin ="UserModel" :ModelStatus="ModelStatus" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import UserLoginView from './user/UserLoginView.vue';
|
||||
|
||||
import UserRegView from './user/UserRegView.vue';
|
||||
const Mdvalue = ref<string>('');
|
||||
|
||||
const ModelStatus = ref('card'); // 传递的状态
|
||||
const Codevalue = ref<string>('');
|
||||
|
||||
// 控制弹框显示/隐藏
|
||||
const visible = ref(false);
|
||||
const ModelInfo=ref('login')
|
||||
const OnChange = (v: string) => {
|
||||
Mdvalue.value = v;
|
||||
console.log(Mdvalue.value);
|
||||
@ -173,14 +179,16 @@ const InChnage = (v: string) => {
|
||||
Codevalue.value = v;
|
||||
console.log(Codevalue.value);
|
||||
};
|
||||
// 控制弹框显示/隐藏
|
||||
const visible = ref(false);
|
||||
|
||||
// 打开登录框
|
||||
const useLogin = () => {
|
||||
visible.value = true;
|
||||
};
|
||||
|
||||
const UserModel = (msg: string) => {
|
||||
ModelInfo.value=msg
|
||||
console.log("收到子组件传来的消息: ", msg);
|
||||
// 处理跳转或其他操作
|
||||
};
|
||||
// 关闭登录框
|
||||
const handleCancel = () => {
|
||||
visible.value = false;
|
||||
@ -196,7 +204,39 @@ const handleCancel = () => {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
/* 遮罩层样式 */
|
||||
.overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5); /* 半透明背景 */
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 1000; /* 确保遮罩层位于最顶层 */
|
||||
}
|
||||
|
||||
/* 弹窗样式 */
|
||||
.login-container {
|
||||
/* background: #0055ff; */
|
||||
/* border-radius: 25px; */
|
||||
/* box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); */
|
||||
/* animation: fadeIn 0.3s ease; 添加淡入动画 */
|
||||
}
|
||||
|
||||
/* 淡入动画效果 */
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
/* 打字机动画效果 */
|
||||
@keyframes typing {
|
||||
from {
|
||||
|
@ -1,70 +1,118 @@
|
||||
<template>
|
||||
<div id="UserCenter">
|
||||
|
||||
<div class="info center" style="display: flex;justify-content: center;align-items: center;flex-direction: row;">
|
||||
<a-menu
|
||||
:style="{ width: '200px', }"
|
||||
:default-open-keys="['0','1','2']"
|
||||
:default-selected-keys="['0_2']"
|
||||
show-collapse-button
|
||||
breakpoint="xl"
|
||||
@collapse="onCollapse"
|
||||
>
|
||||
<a-sub-menu key="0">
|
||||
<template #icon><icon-apps></icon-apps></template>
|
||||
<template #title>我的资料</template>
|
||||
<a-menu-item key="0_0">修改资料</a-menu-item>
|
||||
<a-menu-item key="0_1">修改密码</a-menu-item>
|
||||
|
||||
</a-sub-menu>
|
||||
<a-sub-menu key="1">
|
||||
<template #icon><icon-bug></icon-bug></template>
|
||||
<template #title>我的论坛</template>
|
||||
<a-menu-item key="1_0">我的发帖</a-menu-item>
|
||||
<a-menu-item key="1_1">我的评论</a-menu-item>
|
||||
|
||||
</a-sub-menu>
|
||||
<a-sub-menu key="2">
|
||||
<template #icon><icon-bulb></icon-bulb></template>
|
||||
<template #title>我的题库</template>
|
||||
<a-menu-item key="2_0">做题记录</a-menu-item>
|
||||
</a-sub-menu>
|
||||
</a-menu>
|
||||
<a-card hoverable :style="{ width: '50vw' }" class="aboutCard">
|
||||
<div class="content center" >
|
||||
<UserInfo/>
|
||||
</div>
|
||||
</a-card>
|
||||
<div id="UserCenter" class="user-center">
|
||||
<div class="info">
|
||||
<a-menu
|
||||
:style="{ width: '220px' }"
|
||||
:default-open-keys="['0', '1', '2']"
|
||||
:default-selected-keys="['0_0']"
|
||||
show-collapse-button
|
||||
breakpoint="xl"
|
||||
@collapse="onCollapse"
|
||||
>
|
||||
<a-sub-menu key="0">
|
||||
<template #icon><icon-apps></icon-apps></template>
|
||||
<template #title>我的资料</template>
|
||||
<a-menu-item key="0_0" @click="ChangeStatus(1)">修改资料</a-menu-item>
|
||||
<a-menu-item key="0_1" @click="ChangeStatus(2)">修改密码</a-menu-item>
|
||||
</a-sub-menu>
|
||||
<a-sub-menu key="1">
|
||||
<template #icon><icon-bug></icon-bug></template>
|
||||
<template #title>我的论坛</template>
|
||||
<a-menu-item key="1_0" @click="ChangeStatus(3)">我的发帖</a-menu-item>
|
||||
<a-menu-item key="1_1" @click="ChangeStatus(4)">我的评论</a-menu-item>
|
||||
</a-sub-menu>
|
||||
<a-sub-menu key="2">
|
||||
<template #icon><icon-bulb></icon-bulb></template>
|
||||
<template #title>我的题库</template>
|
||||
<a-menu-item key="2_0" @click="gotoQuestion">做题记录</a-menu-item>
|
||||
</a-sub-menu>
|
||||
</a-menu>
|
||||
<a-card hoverable :style="{ width: '60vw' }" class="aboutCard">
|
||||
<div class="content">
|
||||
<UserInfo v-if="dashStatus==1"/>
|
||||
<UserChangePwd v-else-if="dashStatus==2"/>
|
||||
<UserPost v-else-if="dashStatus==3"/>
|
||||
<UserReview v-else-if="dashStatus==4"/>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import UserInfo from "@/components/User/UserInfo.vue"
|
||||
import {ref} from 'vue'
|
||||
import { useRouter,useRoute } from "vue-router";
|
||||
import UserInfo from "@/components/User/UserInfo.vue";
|
||||
import UserChangePwd from '@/components/User/UserChangePwd.vue';
|
||||
import UserReview from '@/components/User/UserReview.vue';
|
||||
import UserPost from '@/components/User/UserPost.vue';
|
||||
const dashStatus=ref(1)
|
||||
const router=useRouter()
|
||||
const ChangeStatus=(v:number)=>{
|
||||
dashStatus.value=v
|
||||
}
|
||||
const gotoQuestion=()=>{
|
||||
router.push("/history/question/")
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.user-center {
|
||||
padding: 20px; /* 增加整体的内边距 */
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start; /* 垂直对齐 */
|
||||
}
|
||||
|
||||
.center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.content {
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.arco-avatar {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.arco-card-size-medium {
|
||||
font-size: 8px;
|
||||
}
|
||||
|
||||
.save {
|
||||
align-self: flex-end;
|
||||
}
|
||||
:deep(.vch__container .vch__legend) {
|
||||
display: none;
|
||||
|
||||
.aboutCard {
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1); /* 加强阴影效果 */
|
||||
border-radius: 12px; /* 圆角效果 */
|
||||
transition: box-shadow 0.3s; /* 动画过渡效果 */
|
||||
}
|
||||
</style>
|
||||
|
||||
.aboutCard:hover {
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2); /* 鼠标悬停时的阴影效果 */
|
||||
}
|
||||
|
||||
/* 菜单样式 */
|
||||
.a-menu {
|
||||
background-color: #ffffff; /* 菜单背景 */
|
||||
border-radius: 8px; /* 菜单圆角 */
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); /* 菜单阴影 */
|
||||
}
|
||||
|
||||
.a-menu-item:hover {
|
||||
background-color: #e6f7ff; /* 菜单项悬停效果 */
|
||||
}
|
||||
</style>
|
||||
|
@ -37,55 +37,87 @@
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<!-- 底部链接 -->
|
||||
<div class="bottom-text">没有账号?<a @click="goToReg">请注册</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive } from "vue";
|
||||
import { UserControllerService, UserLoginRequest } from "../../../generated";
|
||||
import message from "@arco-design/web-vue/es/message";
|
||||
import { useRouter } from "vue-router";
|
||||
import { useStore } from "vuex";
|
||||
import { reactive, defineEmits, ref, defineProps, withDefaults } from 'vue';
|
||||
import { UserControllerService, UserLoginRequest } from '../../../generated';
|
||||
import message from '@arco-design/web-vue/es/message';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useStore } from 'vuex';
|
||||
|
||||
/**
|
||||
* 表单信息
|
||||
*/
|
||||
const form = reactive({
|
||||
userAccount: "",
|
||||
userPassword: "",
|
||||
userAccount: '',
|
||||
userPassword: '',
|
||||
} as UserLoginRequest);
|
||||
|
||||
// 初始化路由和状态管理
|
||||
const router = useRouter();
|
||||
const store = useStore();
|
||||
|
||||
// 记录用户模式(登录或注册)
|
||||
const userModelInfo = ref('user');
|
||||
|
||||
// 定义自定义事件
|
||||
const emit = defineEmits(['goToReg']);
|
||||
|
||||
// 定义 props 并设置默认值
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
ModelStatus?: string;
|
||||
}>(),
|
||||
{
|
||||
ModelStatus: 'page',
|
||||
}
|
||||
);
|
||||
|
||||
// 输出接收到的 ModelStatus 以进行调试
|
||||
console.log('接收到的 ModelStatus:', props.ModelStatus);
|
||||
|
||||
/**
|
||||
* 跳转到注册页面
|
||||
*/
|
||||
const goToReg = () => {
|
||||
userModelInfo.value = 'reg';
|
||||
emit('goToReg', userModelInfo.value); // 发送事件到父组件
|
||||
|
||||
// 判断 ModelStatus,决定是否跳转
|
||||
if (props.ModelStatus !== 'card') {
|
||||
router.push('/user/reg'); // 执行跳转
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 提交表单
|
||||
* @param data
|
||||
*/
|
||||
const handleSubmit = async () => {
|
||||
const res = await UserControllerService.userLoginUsingPost(form);
|
||||
|
||||
// 登录成功,跳转到主页
|
||||
if (res.code === 0) {
|
||||
await store.dispatch("user/getLoginUser");
|
||||
router.push({
|
||||
path: "/question",
|
||||
replace: true,
|
||||
});
|
||||
await store.dispatch('user/getLoginUser');
|
||||
router.push({ path: '/question', replace: true });
|
||||
} else {
|
||||
message.error("登陆失败," + res.message);
|
||||
message.error('登录失败,' + res.message); // 登录失败的提示
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
/* 样式优化 */
|
||||
#userLoginView {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
|
||||
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@ -111,7 +143,16 @@ h2 {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
/* 底部文本样式 */
|
||||
.bottom-text {
|
||||
text-align: center;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.bottom-text a {
|
||||
color: #0052d9;
|
||||
cursor: pointer;
|
||||
}
|
||||
.login-button {
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -1,72 +1,211 @@
|
||||
<template>
|
||||
<div id="userRegView">
|
||||
<h2 style="margin-bottom: 16px">用户注册</h2>
|
||||
<a-form
|
||||
style="max-width: 480px; margin: 0 auto"
|
||||
label-align="left"
|
||||
auto-label-width
|
||||
:model="form"
|
||||
@submit="handleSubmit"
|
||||
>
|
||||
<a-form-item field="userAccount" label="账号">
|
||||
<a-input v-model="form.userAccount" placeholder="请输入账号" />
|
||||
</a-form-item>
|
||||
<a-form-item field="userPassword" tooltip="密码不少于 8 位" label="密码">
|
||||
<a-input-password
|
||||
v-model="form.userPassword"
|
||||
placeholder="请输入密码"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item field="checkPassword" tooltip="密码不少于 8 位" label="密码">
|
||||
<a-input-password
|
||||
v-model="form.checkPassword"
|
||||
placeholder="请再次输入密码"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-button type="primary" html-type="submit" style="width: 120px">
|
||||
注册
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<div class="register-container">
|
||||
<h2>用户注册</h2>
|
||||
<a-form
|
||||
layout="vertical"
|
||||
:model="form"
|
||||
@submit="handleSubmit"
|
||||
class="register-form"
|
||||
>
|
||||
<a-form-item field="userAccount" label="账号">
|
||||
<a-input
|
||||
v-model="form.userAccount"
|
||||
placeholder="请输入账号"
|
||||
size="large"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item field="userPassword" label="密码">
|
||||
<a-input-password
|
||||
v-model="form.userPassword"
|
||||
placeholder="请输入密码"
|
||||
size="large"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item field="checkPassword" label="确认密码">
|
||||
<a-input-password
|
||||
v-model="form.checkPassword"
|
||||
placeholder="请再次输入密码"
|
||||
size="large"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-button
|
||||
type="primary"
|
||||
html-type="submit"
|
||||
size="large"
|
||||
class="register-button"
|
||||
>
|
||||
注册
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<!-- 底部链接 -->
|
||||
<div class="bottom-text">
|
||||
已有账号?<a @click="goToLogin">请登录</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive } from "vue";
|
||||
import { UserControllerService, UserLoginRequest } from "../../../generated";
|
||||
import message from "@arco-design/web-vue/es/message";
|
||||
import { useRouter } from "vue-router";
|
||||
import { useStore } from "vuex";
|
||||
import { reactive, ref, defineEmits, defineProps, withDefaults } from 'vue';
|
||||
import { UserControllerService, UserLoginRequest } from '../../../generated';
|
||||
import message from '@arco-design/web-vue/es/message';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
/**
|
||||
* Props 定义
|
||||
*/
|
||||
interface Status {
|
||||
ModelStatus?: string; // 可选的状态属性
|
||||
}
|
||||
|
||||
// 使用 withDefaults 设置 ModelStatus 的默认值
|
||||
const props = withDefaults(defineProps<Status>(), {
|
||||
ModelStatus: 'page', // 默认值为 'page'
|
||||
});
|
||||
|
||||
/**
|
||||
* 表单信息
|
||||
*/
|
||||
const form = reactive({
|
||||
userAccount: "",
|
||||
userPassword: "",
|
||||
checkPassword:""
|
||||
userAccount: '',
|
||||
userPassword: '',
|
||||
checkPassword: '',
|
||||
} as UserLoginRequest);
|
||||
|
||||
// 路由实例
|
||||
const router = useRouter();
|
||||
const store = useStore();
|
||||
|
||||
/**
|
||||
* Emit 事件定义
|
||||
*/
|
||||
const emit = defineEmits(['goToLogin']);
|
||||
|
||||
/**
|
||||
* 当前模式信息
|
||||
*/
|
||||
const ModelInfo = ref('login');
|
||||
|
||||
/**
|
||||
* 提交表单
|
||||
* @param data
|
||||
*/
|
||||
const handleSubmit = async () => {
|
||||
if (!isPasswordValid()) return; // 检查密码有效性
|
||||
|
||||
const res = await UserControllerService.userRegisterUsingPost(form);
|
||||
// 注册成功,跳转到主页
|
||||
handleResponse(res); // 处理响应
|
||||
};
|
||||
|
||||
/**
|
||||
* 校验密码是否一致
|
||||
* @returns 是否有效
|
||||
*/
|
||||
const isPasswordValid = (): boolean => {
|
||||
if (form.userPassword !== form.checkPassword) {
|
||||
message.error('两次输入的密码不一致');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理响应
|
||||
* @param res API 响应
|
||||
*/
|
||||
const handleResponse = (res: any) => {
|
||||
if (res.code === 0) {
|
||||
message.success(res.message);
|
||||
// await store.dispatch("user/getLoginUser");
|
||||
router.push({
|
||||
path: "/user/login",
|
||||
replace: true,
|
||||
});
|
||||
message.success(res.message);
|
||||
router.push({ path: '/user/login', replace: true });
|
||||
} else {
|
||||
message.error("注册" + res.message);
|
||||
message.error('注册失败,' + res.message);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 跳转到登录页面
|
||||
*/
|
||||
const goToLogin = () => {
|
||||
if (props.ModelStatus !== 'card') {
|
||||
router.push('/user/login');
|
||||
}
|
||||
emit('goToLogin', ModelInfo.value); // 触发事件
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
/* 优化样式 */
|
||||
#userRegView {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.register-container {
|
||||
background: #fff;
|
||||
padding: 40px 30px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
max-width: 400px;
|
||||
width: 100%;
|
||||
animation: fadeIn 0.5s ease;
|
||||
}
|
||||
|
||||
h2 {
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
color: #0052d9;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.register-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.register-button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 底部文本样式 */
|
||||
.bottom-text {
|
||||
text-align: center;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.bottom-text a {
|
||||
color: #0052d9;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 动画效果 */
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式优化 */
|
||||
@media (max-width: 600px) {
|
||||
.register-container {
|
||||
padding: 30px 20px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user