美观和汉化

This commit is contained in:
Chester.X 2024-07-05 18:24:26 +08:00
parent d087dc171f
commit ca5ca2bb95
6 changed files with 313 additions and 129 deletions

View File

@ -1,5 +1,6 @@
import Course from '../views/course-management/Course.vue';
import CourseList from '../views/course-management/CourseList.vue';
import BackgroundWrapper from "@views/course-management/BackgroundWrapper.vue";
export default [
{
@ -12,5 +13,11 @@ export default [
path: '/courseList',
name: 'CourseList',
component: CourseList
},
{
path: '/backgroundWrapper',
name: 'BackgroundWrapper',
component: BackgroundWrapper
}
];

View File

@ -18,11 +18,12 @@ const login = async () => {
const response = await AuthenticationService.login(credentials);
if (response.status === 200) {
store.commit('authentication/setUser', { token: response.data.token });
}
router.push("/profile");
ElMessage.success('登录成功');
}
} catch (error) {
ElMessage.error('Invalid username or password');
console.error("Login error:", error);
ElMessage.error('用户名或密码错误');
console.error("登录错误:", error);
}
};
@ -37,10 +38,10 @@ const goToRegister = () => {
<h1>用户登录</h1>
<el-form @submit.prevent="login" label-width="100px">
<el-form-item label="用户名:">
<el-input v-model="credentials.username" id="username"/>
<el-input v-model="credentials.username" id="username" class="short-input"/>
</el-form-item>
<el-form-item label="密码:">
<el-input v-model="credentials.password" id="password" type="password"/>
<el-input v-model="credentials.password" id="password" type="password" class="short-input"/>
</el-form-item>
<el-form-item>
<el-button type="primary" native-type="submit">登录</el-button>
@ -64,15 +65,29 @@ const goToRegister = () => {
.login-container {
max-width: 400px;
width: 100%;
padding: 20px;
padding: 30px;
border: 1px solid #ebeef5;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
background-color: #fff;
border-radius: 10px;
box-shadow: 0 3px 15px rgba(0, 0, 0, 0.2);
background-color: rgba(255, 255, 255, 0.9);
}
h1 {
text-align: center;
margin-bottom: 30px;
font-size: 24px;
color: #333;
}
.el-form-item {
margin-bottom: 20px;
}
.short-input {
width: 80%;
}
.el-button {
margin-right: 10px;
}
</style>

View File

@ -1,13 +1,14 @@
<template>
<div class="profile-wrapper">
<div class="profile-container">
<el-button type="danger" @click="confirmLogout" class="logout-button">注销</el-button>
<el-tabs v-model="activeTab">
<el-tab-pane label="用户信息" name="userInformation"></el-tab-pane>
<el-tab-pane label="信息修改" name="profile"></el-tab-pane>
<el-tab-pane label="更改密码" name="changePassword"></el-tab-pane>
</el-tabs>
<div v-if="activeTab === 'userInformation'">
<div v-if="activeTab === 'userInformation'" class="user-information">
<h2>用户信息</h2>
<div class="user-info">
<div class="user-details">
@ -18,25 +19,25 @@
<p>创建日期: {{ user.createdDate }}</p>
</div>
<div class="user-avatar">
<img src= '@assets/avatar.jpg' alt="User Avatar" />
<img src='@assets/avatar.jpg' alt="用户头像" />
</div>
</div>
</div>
<div v-if="activeTab === 'profile'">
<div v-if="activeTab === 'profile'" class="centered-content">
<h2>信息修改</h2>
<el-form @submit.prevent="updateProfile" label-width="120px" class="profile-form">
<el-form @submit.prevent="updateProfile" label-width="120px" class="centered-form profile-form">
<el-form-item label="用户名:">
<el-input v-model="user.username" id="username" disabled />
<el-input v-model="user.username" id="username" class="short-input" disabled />
</el-form-item>
<el-form-item label="电子邮箱:">
<el-input v-model="user.email" id="email" />
<el-input v-model="user.email" id="email" class="short-input" />
</el-form-item>
<el-form-item label="电话号码:">
<el-input v-model="user.phoneNumber" id="phoneNumber" />
<el-input v-model="user.phoneNumber" id="phoneNumber" class="short-input" />
</el-form-item>
<el-form-item label="所属企业:">
<el-input v-model="user.company" id="company" />
<el-input v-model="user.company" id="company" class="short-input" />
</el-form-item>
<el-form-item>
<el-button type="primary" native-type="submit">更新</el-button>
@ -44,17 +45,20 @@
</el-form>
</div>
<div v-if="activeTab === 'changePassword'">
<div v-if="activeTab === 'changePassword'" class="centered-content">
<h2>更改密码</h2>
<el-form @submit.prevent="changePassword" label-width="120px" class="password-form">
<el-form @submit.prevent="changePassword" label-width="120px" class="centered-form password-form">
<el-form-item label="旧密码:">
<el-input v-model="passwords.oldPassword" id="oldPassword" type="password" />
<el-input v-model="passwords.oldPassword" :type="showOldPassword ? 'text' : 'password'" class="short-password-input" />
<el-button @click="togglePasswordVisibility('oldPassword')">{{ showOldPassword ? '隐藏' : '显示' }}</el-button>
</el-form-item>
<el-form-item label="新密码:">
<el-input v-model="passwords.newPassword" id="newPassword" type="password" />
<el-input v-model="passwords.newPassword" :type="showNewPassword ? 'text' : 'password'" class="short-password-input" />
<el-button @click="togglePasswordVisibility('newPassword')">{{ showNewPassword ? '隐藏' : '显示' }}</el-button>
</el-form-item>
<el-form-item label="再次确认:">
<el-input v-model="passwords.confirmPassword" id="confirmPassword" type="password" />
<el-input v-model="passwords.confirmPassword" :type="showConfirmPassword ? 'text' : 'password'" class="short-password-input" />
<el-button @click="togglePasswordVisibility('confirmPassword')">{{ showConfirmPassword ? '隐藏' : '显示' }}</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" native-type="submit">更改</el-button>
@ -68,10 +72,12 @@
<script setup>
import { ref, onMounted } from 'vue';
import { useStore } from 'vuex';
import { ElMessage } from 'element-plus';
import { useRouter } from 'vue-router';
import { ElMessage, ElMessageBox } from 'element-plus'; // ElMessageBox
import AuthenticationService from '../../services/authenticationService';
const store = useStore();
const router = useRouter();
const activeTab = ref('userInformation');
const user = ref({
@ -89,6 +95,10 @@ const passwords = ref({
confirmPassword: ''
});
const showOldPassword = ref(false);
const showNewPassword = ref(false);
const showConfirmPassword = ref(false);
const token = store.getters['authentication/token'];
const fetchUserInfo = async () => {
@ -96,24 +106,24 @@ const fetchUserInfo = async () => {
const response = await AuthenticationService.getUserInfo(token);
user.value = response.data;
} catch (error) {
console.error("Error fetching user info:", error);
console.error("获取用户信息错误:", error);
}
};
const updateProfile = async () => {
try {
await AuthenticationService.updateUserInfo(user.value);
ElMessage.success('Profile updated successfully');
ElMessage.success('个人信息更新成功');
await fetchUserInfo();
} catch (error) {
console.error("Error updating profile:", error);
ElMessage.error('Error updating profile');
console.error("更新个人信息错误:", error);
ElMessage.error('更新个人信息失败');
}
};
const changePassword = async () => {
if (passwords.value.newPassword !== passwords.value.confirmPassword) {
ElMessage.error('New password and confirm password do not match');
ElMessage.error('新密码和确认密码不一致');
return;
}
try {
@ -122,13 +132,36 @@ const changePassword = async () => {
oldPassword: passwords.value.oldPassword,
newPassword: passwords.value.newPassword
});
ElMessage.success('Password changed successfully');
ElMessage.success('密码更改成功');
} catch (error) {
console.error("Error changing password:", error);
ElMessage.error('Old password is incorrect');
console.error("更改密码错误:", error);
ElMessage.error('旧密码错误');
}
};
const togglePasswordVisibility = (field) => {
if (field === 'oldPassword') {
showOldPassword.value = !showOldPassword.value;
} else if (field === 'newPassword') {
showNewPassword.value = !showNewPassword.value;
} else if (field === 'confirmPassword') {
showConfirmPassword.value = !showConfirmPassword.value;
}
};
const confirmLogout = () => {
ElMessageBox.confirm('是否确认注销?', '注销确认', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}).then(logout).catch(() => {});
};
const logout = () => {
store.commit('authentication/logout');
router.push('/login');
};
onMounted(() => {
fetchUserInfo();
});
@ -136,54 +169,83 @@ onMounted(() => {
<style scoped>
.profile-wrapper {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
background-image: url('@public/background2.jpg');
background-size: cover;
background-position: center;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
background-image: url('@public/background2.jpg');
background-size: cover;
background-position: center;
}
.profile-container {
max-width: 600px;
width: 100%;
padding: 20px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
max-width: 600px;
width: 100%;
padding: 20px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
position: relative;
}
h1, h2 {
text-align: center;
margin-bottom: 20px;
text-align: center;
margin-bottom: 20px;
}
.profile-form, .password-form {
margin-bottom: 30px;
margin-bottom: 30px;
}
.centered-content {
display: flex;
flex-direction: column;
align-items: center;
}
.centered-form {
width: 100%;
max-width: 400px;
}
.user-info {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
border-top: 1px solid #ebeef5;
margin-top: 20px;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 20px 20px 80px;
border-top: 1px solid #ebeef5;
margin-top: 20px;
}
.user-details {
flex: 1;
flex: 1;
padding-right: 20px;
}
.user-avatar {
margin-left: 20px;
padding-right: 50px;
}
.user-avatar img {
width: 100px;
height: 100px;
border-radius: 50%;
object-fit: cover;
width: 150px;
height: 150px;
border-radius: 50%;
object-fit: cover;
}
.short-input {
width: 90%;
}
.short-password-input {
width: 80%;
}
.logout-button {
position: absolute;
top: 10px;
right: 10px;
z-index: 1000;
padding: 10px 20px;
}
</style>

View File

@ -1,34 +1,34 @@
<template>
<el-container class="register-container">
<el-main>
<el-main class="register-main">
<el-card class="register-card">
<el-header>
<h2>注册</h2>
</el-header>
<el-form @submit.prevent="register" label-position="top" class="register-form">
<el-form-item label="用户名" required>
<el-input type="text" v-model="username"></el-input>
<el-input class="form-input" type="text" v-model="username"></el-input>
</el-form-item>
<el-form-item label="密码" required>
<el-input type="password" v-model="password"></el-input>
<el-input class="form-input" type="password" v-model="password"></el-input>
</el-form-item>
<el-form-item label="电子邮箱" required>
<el-input type="email" v-model="email"></el-input>
<el-input class="form-input" type="email" v-model="email"></el-input>
</el-form-item>
<el-form-item label="电话号码" required>
<el-input type="text" v-model="phoneNumber"></el-input>
<el-input class="form-input" type="text" v-model="phoneNumber"></el-input>
</el-form-item>
<el-form-item label="所属企业" required>
<el-input type="text" v-model="company"></el-input>
<el-input class="form-input" type="text" v-model="company"></el-input>
</el-form-item>
<el-form-item label="选择身份">
<el-select v-model="role" placeholder="Select role">
<el-select class="form-input" v-model="role" placeholder="选择身份">
<el-option label="租户" value="USER"></el-option>
<el-option label="管理员" value="ADMIN"></el-option>
</el-select>
</el-form-item>
<el-form-item label="请输入验证码" required>
<el-input type="text" v-model="verificationCode"></el-input>
<el-input class="form-input" type="text" v-model="verificationCode"></el-input>
<el-button class="verification-button" type="primary" @click="getVerificationCode">获取验证码</el-button>
</el-form-item>
<el-form-item>
@ -64,8 +64,28 @@ const getVerificationCode = async () => {
};
const register = async () => {
if (!username.value) {
ElMessage.error('用户名不能为空!');
return;
}
if (!password.value) {
ElMessage.error('密码不能为空!');
return;
}
if (!email.value) {
ElMessage.error('电子邮箱不能为空!');
return;
}
if (!phoneNumber.value) {
ElMessage.error('电话号码不能为空!');
return;
}
if (!company.value) {
ElMessage.error('所属企业不能为空!');
return;
}
if (!verificationCode.value) {
message.value = '验证码不能为空!';
ElMessage.error('验证码不能为空!');
return;
}
try {
@ -80,7 +100,7 @@ const register = async () => {
message.value = response.data.message;
router.push('/login');
} catch (error) {
console.error("Registration failed:", error.response.data.message);
console.error("注册失败:", error.response.data.message);
message.value = error.response.data.message;
}
};
@ -93,7 +113,6 @@ const goToLogin = () => {
<style scoped>
.register-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
@ -101,7 +120,12 @@ const goToLogin = () => {
background-size: cover;
background-position: center;
padding: 20px;
overflow: hidden;
}
.register-main {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
}
@ -111,11 +135,18 @@ const goToLogin = () => {
border-radius: 8px;
background-color: white;
width: 100%;
max-width: 300px;
max-width: 350px; /* 调整卡片的宽度 */
overflow: hidden;
}
.register-form {
width: 100%;
max-height: 400px;
overflow-y: auto; /* 使表单内容可滚动 */
}
.el-form-item {
margin-bottom: 15px; /* 调整表单项之间的间距 */
}
.el-header h2 {
@ -123,11 +154,36 @@ const goToLogin = () => {
margin: 0 0 20px;
}
.form-input {
width: calc(100% - 12px); /* 调整输入框的宽度,与滚动条保持距离 */
padding-right: 12px; /* 增加右侧内边距 */
box-sizing: border-box; /* 确保宽度包含内边距 */
}
.verification-button {
margin-top: 20px;
margin-top: 10px; /* 调整验证码按钮上方的间距 */
}
.el-alert {
margin-top: 20px;
}
/* 自定义滚动条样式 */
.register-form::-webkit-scrollbar {
width: 8px; /* 滚动条宽度 */
}
.register-form::-webkit-scrollbar-track {
background: #f1f1f1; /* 滚动条轨道颜色 */
border-radius: 10px;
}
.register-form::-webkit-scrollbar-thumb {
background: #888; /* 滚动条滑块颜色 */
border-radius: 10px;
}
.register-form::-webkit-scrollbar-thumb:hover {
background: #555; /* 滚动条滑块在悬停时的颜色 */
}
</style>

View File

@ -0,0 +1,17 @@
<template>
<div class="background-wrapper">
<slot></slot>
</div>
</template>
<style scoped>
.background-wrapper {
background: url('@public/background2.jpg') no-repeat center center fixed;
background-size: cover;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
</style>

View File

@ -5,6 +5,7 @@ import axios from "axios";
import { useStore } from "vuex";
import { useRouter } from "vue-router";
import Course from "@views/course-management/Course.vue";
import BackgroundWrapper from './BackgroundWrapper.vue';
const router = useRouter();
const store = useStore();
@ -31,7 +32,7 @@ const loadCourses = async (forceReload = false) => {
allCoursesData.value = [];
}
if (firstTimeLoad.value || allCoursesData.value.length < (currentPage.value * pageSize.value) && (currentPage.value * pageSize.value) <= coursesCount) {
if (firstTimeLoad.value || allCoursesData.value.length < (currentPage.value * pageSize.value) && (currentPage.value * pageSize.value) <= coursesCount.value) {
let params = {
token: token,
start: allCoursesData.value.length,
@ -59,7 +60,7 @@ const handleSearch = async () => {
const response = await axios.get('/api/courses/search', {
params: {
token: token,
title: searchTitle.value || '', //
title: searchTitle.value || '',
author: searchAuthor.value || '',
description: searchDescription.value || '',
sortOrder: sortOrder.value || '',
@ -98,6 +99,10 @@ const handleSort = async () => {
}
});
const data = response.data;
//
console.log(data.courseList);
coursesCount.value = data.courseCount;
allCoursesData.value = data.courseList;
coursesData.value = allCoursesData.value.slice(0, pageSize.value);
@ -164,6 +169,8 @@ const handleDeleteInTable = async (index) => {
</script>
<template>
<BackgroundWrapper>
<div class="center-wrapper">
<div class="container">
<div class="search-container">
<el-form inline>
@ -222,11 +229,31 @@ const handleDeleteInTable = async (index) => {
</el-pagination>
</div>
</div>
</div>
</BackgroundWrapper>
</template>
<style scoped>
html, body {
height: 100%;
margin: 0;
}
.center-wrapper {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
.container {
padding: 20px;
background: rgba(255, 255, 255, 0.8); /* 为了让内容清晰,可加上一层半透明白色背景 */
border-radius: 15px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
max-width: 800px; /* 控制页面内容宽度 */
width: 100%;
}
.search-container {