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();
|
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> -->
|
<!-- <p>已登录</p> -->
|
||||||
</a-avatar>
|
</a-avatar>
|
||||||
<template #content>
|
<template #content>
|
||||||
<a-doption>
|
<a-doption @click="gotoCenter()">
|
||||||
<a-button type="text">
|
<a-button type="text">
|
||||||
<icon-user style=" font-size: 20px;" />
|
<icon-user style=" font-size: 20px;" />
|
||||||
个人中心
|
个人中心
|
||||||
@ -167,7 +167,10 @@ const doMenuClick = (key: string) => {
|
|||||||
path: key,
|
path: key,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
// 跳转到用户中心
|
||||||
|
const gotoCenter=()=>{
|
||||||
|
router.push('/user/center')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<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>
|
<template>
|
||||||
<div class="info">
|
<div class="info" style="align-items: center;">
|
||||||
<div class="avatar" style="display: flex;justify-content: center;">
|
<div class="avatar" style="display: flex;justify-content: center;align-items: center;width: 50%;">
|
||||||
<a-avatar id="userAvatar" @click="onClcik" :style="{ backgroundColor: '#0A65CC' }">
|
|
||||||
|
<a-avatar :size="100" id="userAvatar" @click="onClcik" :style="{ backgroundColor: '#0A65CC' }">
|
||||||
|
|
||||||
<img v-if="form.userAvatar" class="avatar-image" alt="avatar" :src="form.userAvatar" />
|
<img v-if="form.userAvatar" class="avatar-image" alt="avatar" :src="form.userAvatar" />
|
||||||
<IconUser v-else />
|
<IconUser v-else />
|
||||||
<template #trigger-icon>
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 登录弹框 -->
|
<!-- 登录弹框 -->
|
||||||
<a-modal v-model:visible="visible" @cancel="handleCancel" :footer="null" >
|
<div v-if="visible" class="overlay" @click.self="handleCancel" >
|
||||||
<UserLoginView />
|
<div class="login-container">
|
||||||
</a-modal>
|
<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>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import UserLoginView from './user/UserLoginView.vue';
|
import UserLoginView from './user/UserLoginView.vue';
|
||||||
|
import UserRegView from './user/UserRegView.vue';
|
||||||
const Mdvalue = ref<string>('');
|
const Mdvalue = ref<string>('');
|
||||||
|
const ModelStatus = ref('card'); // 传递的状态
|
||||||
const Codevalue = ref<string>('');
|
const Codevalue = ref<string>('');
|
||||||
|
// 控制弹框显示/隐藏
|
||||||
|
const visible = ref(false);
|
||||||
|
const ModelInfo=ref('login')
|
||||||
const OnChange = (v: string) => {
|
const OnChange = (v: string) => {
|
||||||
Mdvalue.value = v;
|
Mdvalue.value = v;
|
||||||
console.log(Mdvalue.value);
|
console.log(Mdvalue.value);
|
||||||
@ -173,14 +179,16 @@ const InChnage = (v: string) => {
|
|||||||
Codevalue.value = v;
|
Codevalue.value = v;
|
||||||
console.log(Codevalue.value);
|
console.log(Codevalue.value);
|
||||||
};
|
};
|
||||||
// 控制弹框显示/隐藏
|
|
||||||
const visible = ref(false);
|
|
||||||
|
|
||||||
// 打开登录框
|
// 打开登录框
|
||||||
const useLogin = () => {
|
const useLogin = () => {
|
||||||
visible.value = true;
|
visible.value = true;
|
||||||
};
|
};
|
||||||
|
const UserModel = (msg: string) => {
|
||||||
|
ModelInfo.value=msg
|
||||||
|
console.log("收到子组件传来的消息: ", msg);
|
||||||
|
// 处理跳转或其他操作
|
||||||
|
};
|
||||||
// 关闭登录框
|
// 关闭登录框
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
visible.value = false;
|
visible.value = false;
|
||||||
@ -196,7 +204,39 @@ const handleCancel = () => {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: 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 {
|
@keyframes typing {
|
||||||
from {
|
from {
|
||||||
|
@ -1,70 +1,118 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="UserCenter">
|
<div id="UserCenter" class="user-center">
|
||||||
|
<div class="info">
|
||||||
<div class="info center" style="display: flex;justify-content: center;align-items: center;flex-direction: row;">
|
<a-menu
|
||||||
<a-menu
|
:style="{ width: '220px' }"
|
||||||
:style="{ width: '200px', }"
|
:default-open-keys="['0', '1', '2']"
|
||||||
:default-open-keys="['0','1','2']"
|
:default-selected-keys="['0_0']"
|
||||||
:default-selected-keys="['0_2']"
|
show-collapse-button
|
||||||
show-collapse-button
|
breakpoint="xl"
|
||||||
breakpoint="xl"
|
@collapse="onCollapse"
|
||||||
@collapse="onCollapse"
|
>
|
||||||
>
|
<a-sub-menu key="0">
|
||||||
<a-sub-menu key="0">
|
<template #icon><icon-apps></icon-apps></template>
|
||||||
<template #icon><icon-apps></icon-apps></template>
|
<template #title>我的资料</template>
|
||||||
<template #title>我的资料</template>
|
<a-menu-item key="0_0" @click="ChangeStatus(1)">修改资料</a-menu-item>
|
||||||
<a-menu-item key="0_0">修改资料</a-menu-item>
|
<a-menu-item key="0_1" @click="ChangeStatus(2)">修改密码</a-menu-item>
|
||||||
<a-menu-item key="0_1">修改密码</a-menu-item>
|
</a-sub-menu>
|
||||||
|
<a-sub-menu key="1">
|
||||||
</a-sub-menu>
|
<template #icon><icon-bug></icon-bug></template>
|
||||||
<a-sub-menu key="1">
|
<template #title>我的论坛</template>
|
||||||
<template #icon><icon-bug></icon-bug></template>
|
<a-menu-item key="1_0" @click="ChangeStatus(3)">我的发帖</a-menu-item>
|
||||||
<template #title>我的论坛</template>
|
<a-menu-item key="1_1" @click="ChangeStatus(4)">我的评论</a-menu-item>
|
||||||
<a-menu-item key="1_0">我的发帖</a-menu-item>
|
</a-sub-menu>
|
||||||
<a-menu-item key="1_1">我的评论</a-menu-item>
|
<a-sub-menu key="2">
|
||||||
|
<template #icon><icon-bulb></icon-bulb></template>
|
||||||
</a-sub-menu>
|
<template #title>我的题库</template>
|
||||||
<a-sub-menu key="2">
|
<a-menu-item key="2_0" @click="gotoQuestion">做题记录</a-menu-item>
|
||||||
<template #icon><icon-bulb></icon-bulb></template>
|
</a-sub-menu>
|
||||||
<template #title>我的题库</template>
|
</a-menu>
|
||||||
<a-menu-item key="2_0">做题记录</a-menu-item>
|
<a-card hoverable :style="{ width: '60vw' }" class="aboutCard">
|
||||||
</a-sub-menu>
|
<div class="content">
|
||||||
</a-menu>
|
<UserInfo v-if="dashStatus==1"/>
|
||||||
<a-card hoverable :style="{ width: '50vw' }" class="aboutCard">
|
<UserChangePwd v-else-if="dashStatus==2"/>
|
||||||
<div class="content center" >
|
<UserPost v-else-if="dashStatus==3"/>
|
||||||
<UserInfo/>
|
<UserReview v-else-if="dashStatus==4"/>
|
||||||
</div>
|
</div>
|
||||||
</a-card>
|
</a-card>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<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>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.user-center {
|
||||||
|
padding: 20px; /* 增加整体的内边距 */
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start; /* 垂直对齐 */
|
||||||
|
}
|
||||||
|
|
||||||
.center {
|
.center {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.arco-avatar {
|
.arco-avatar {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
height: 80px;
|
height: 80px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.arco-card-size-medium {
|
.arco-card-size-medium {
|
||||||
font-size: 8px;
|
font-size: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.save {
|
.save {
|
||||||
align-self: flex-end;
|
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-button>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
|
<!-- 底部链接 -->
|
||||||
|
<div class="bottom-text">没有账号?<a @click="goToReg">请注册</a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive } from "vue";
|
import { reactive, defineEmits, ref, defineProps, withDefaults } from 'vue';
|
||||||
import { UserControllerService, UserLoginRequest } from "../../../generated";
|
import { UserControllerService, UserLoginRequest } from '../../../generated';
|
||||||
import message from "@arco-design/web-vue/es/message";
|
import message from '@arco-design/web-vue/es/message';
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from 'vue-router';
|
||||||
import { useStore } from "vuex";
|
import { useStore } from 'vuex';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表单信息
|
* 表单信息
|
||||||
*/
|
*/
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
userAccount: "",
|
userAccount: '',
|
||||||
userPassword: "",
|
userPassword: '',
|
||||||
} as UserLoginRequest);
|
} as UserLoginRequest);
|
||||||
|
|
||||||
|
// 初始化路由和状态管理
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const store = useStore();
|
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 handleSubmit = async () => {
|
||||||
const res = await UserControllerService.userLoginUsingPost(form);
|
const res = await UserControllerService.userLoginUsingPost(form);
|
||||||
|
|
||||||
// 登录成功,跳转到主页
|
// 登录成功,跳转到主页
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
await store.dispatch("user/getLoginUser");
|
await store.dispatch('user/getLoginUser');
|
||||||
router.push({
|
router.push({ path: '/question', replace: true });
|
||||||
path: "/question",
|
|
||||||
replace: true,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
message.error("登陆失败," + res.message);
|
message.error('登录失败,' + res.message); // 登录失败的提示
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
/* 样式优化 */
|
/* 样式优化 */
|
||||||
#userLoginView {
|
#userLoginView {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +143,16 @@ h2 {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
/* 底部文本样式 */
|
||||||
|
.bottom-text {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-text a {
|
||||||
|
color: #0052d9;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
.login-button {
|
.login-button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -1,72 +1,211 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="userRegView">
|
<div id="userRegView">
|
||||||
<h2 style="margin-bottom: 16px">用户注册</h2>
|
<div class="register-container">
|
||||||
<a-form
|
<h2>用户注册</h2>
|
||||||
style="max-width: 480px; margin: 0 auto"
|
<a-form
|
||||||
label-align="left"
|
layout="vertical"
|
||||||
auto-label-width
|
:model="form"
|
||||||
:model="form"
|
@submit="handleSubmit"
|
||||||
@submit="handleSubmit"
|
class="register-form"
|
||||||
>
|
>
|
||||||
<a-form-item field="userAccount" label="账号">
|
<a-form-item field="userAccount" label="账号">
|
||||||
<a-input v-model="form.userAccount" placeholder="请输入账号" />
|
<a-input
|
||||||
</a-form-item>
|
v-model="form.userAccount"
|
||||||
<a-form-item field="userPassword" tooltip="密码不少于 8 位" label="密码">
|
placeholder="请输入账号"
|
||||||
<a-input-password
|
size="large"
|
||||||
v-model="form.userPassword"
|
allow-clear
|
||||||
placeholder="请输入密码"
|
/>
|
||||||
/>
|
</a-form-item>
|
||||||
</a-form-item>
|
<a-form-item field="userPassword" label="密码">
|
||||||
<a-form-item field="checkPassword" tooltip="密码不少于 8 位" label="密码">
|
<a-input-password
|
||||||
<a-input-password
|
v-model="form.userPassword"
|
||||||
v-model="form.checkPassword"
|
placeholder="请输入密码"
|
||||||
placeholder="请再次输入密码"
|
size="large"
|
||||||
/>
|
allow-clear
|
||||||
</a-form-item>
|
/>
|
||||||
<a-form-item>
|
</a-form-item>
|
||||||
<a-button type="primary" html-type="submit" style="width: 120px">
|
<a-form-item field="checkPassword" label="确认密码">
|
||||||
注册
|
<a-input-password
|
||||||
</a-button>
|
v-model="form.checkPassword"
|
||||||
</a-form-item>
|
placeholder="请再次输入密码"
|
||||||
</a-form>
|
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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive } from "vue";
|
import { reactive, ref, defineEmits, defineProps, withDefaults } from 'vue';
|
||||||
import { UserControllerService, UserLoginRequest } from "../../../generated";
|
import { UserControllerService, UserLoginRequest } from '../../../generated';
|
||||||
import message from "@arco-design/web-vue/es/message";
|
import message from '@arco-design/web-vue/es/message';
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from 'vue-router';
|
||||||
import { useStore } from "vuex";
|
|
||||||
|
/**
|
||||||
|
* Props 定义
|
||||||
|
*/
|
||||||
|
interface Status {
|
||||||
|
ModelStatus?: string; // 可选的状态属性
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 withDefaults 设置 ModelStatus 的默认值
|
||||||
|
const props = withDefaults(defineProps<Status>(), {
|
||||||
|
ModelStatus: 'page', // 默认值为 'page'
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表单信息
|
* 表单信息
|
||||||
*/
|
*/
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
userAccount: "",
|
userAccount: '',
|
||||||
userPassword: "",
|
userPassword: '',
|
||||||
checkPassword:""
|
checkPassword: '',
|
||||||
} as UserLoginRequest);
|
} as UserLoginRequest);
|
||||||
|
|
||||||
|
// 路由实例
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const store = useStore();
|
|
||||||
|
/**
|
||||||
|
* Emit 事件定义
|
||||||
|
*/
|
||||||
|
const emit = defineEmits(['goToLogin']);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前模式信息
|
||||||
|
*/
|
||||||
|
const ModelInfo = ref('login');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提交表单
|
* 提交表单
|
||||||
* @param data
|
|
||||||
*/
|
*/
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
|
if (!isPasswordValid()) return; // 检查密码有效性
|
||||||
|
|
||||||
const res = await UserControllerService.userRegisterUsingPost(form);
|
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) {
|
if (res.code === 0) {
|
||||||
message.success(res.message);
|
message.success(res.message);
|
||||||
// await store.dispatch("user/getLoginUser");
|
router.push({ path: '/user/login', replace: true });
|
||||||
router.push({
|
|
||||||
path: "/user/login",
|
|
||||||
replace: true,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
message.error("注册" + res.message);
|
message.error('注册失败,' + res.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳转到登录页面
|
||||||
|
*/
|
||||||
|
const goToLogin = () => {
|
||||||
|
if (props.ModelStatus !== 'card') {
|
||||||
|
router.push('/user/login');
|
||||||
|
}
|
||||||
|
emit('goToLogin', ModelInfo.value); // 触发事件
|
||||||
|
};
|
||||||
</script>
|
</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