34 changed files with 315 additions and 384 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1 @@ |
|||
|
@ -1,58 +1,48 @@ |
|||
#include <cstdio> |
|||
#include <iostream> |
|||
#include <iostream> |
|||
#include <string> |
|||
#include <websocketpp/config/asio_no_tls.hpp> |
|||
#include <websocketpp/server.hpp> |
|||
// 0.定义server_t类型
|
|||
typedef websocketpp::server<websocketpp::config::asio> server_t; |
|||
|
|||
void OnOpen(websocketpp::connection_hdl hdl) |
|||
{ |
|||
std::cout << "Websocket长连接建立成功" << std::endl; |
|||
} |
|||
|
|||
void OnClose(websocketpp::connection_hdl hdl) |
|||
{ |
|||
std::cout << "Websocket长连接断开" << std::endl; |
|||
} |
|||
|
|||
void OnMessage(server_t* svr, websocketpp::connection_hdl hdl, server_t::message_ptr msg) |
|||
{ |
|||
std::string body = msg->get_payload(); |
|||
std::cout << "Get Msg: " << body << std::endl; |
|||
|
|||
auto conn = svr->get_con_from_hdl(hdl); |
|||
|
|||
conn->send(body + "-Response", websocketpp::frame::opcode::value::text); |
|||
#include <nlohmann/json.hpp> |
|||
|
|||
using json = nlohmann::json; |
|||
using websocketpp::lib::placeholders::_1; |
|||
using websocketpp::lib::placeholders::_2; |
|||
using websocketpp::lib::bind; |
|||
|
|||
typedef websocketpp::server<websocketpp::config::asio> server; |
|||
|
|||
// 消息处理回调函数
|
|||
void on_message(server* s, websocketpp::connection_hdl hdl, server::message_ptr msg) { |
|||
std::string payload = msg->get_payload(); |
|||
std::cout << "Received JSON string: " << payload << std::endl; |
|||
|
|||
// 解析JSON字符串
|
|||
try { |
|||
json j = json::parse(payload); |
|||
std::cout << "Parsed JSON: " << j.dump(4) << std::endl; // 使用dump(4)美化输出
|
|||
} |
|||
catch (json::parse_error& e) { |
|||
std::cerr << "Failed to parse JSON: " << e.what() << std::endl; |
|||
} |
|||
} |
|||
|
|||
int main() |
|||
{ |
|||
// 1.实例化服务器对象
|
|||
server_t svr; |
|||
|
|||
// 2.初始化日志输出 --> 关闭日志输出
|
|||
svr.set_access_channels(websocketpp::log::alevel::none); |
|||
int main() { |
|||
server ws_server; |
|||
|
|||
// 3.初始化ASIO框架
|
|||
svr.init_asio(); |
|||
// 初始化服务器
|
|||
ws_server.init_asio(); |
|||
|
|||
// 4.设置消息处理/连接握手成功/连接关闭回调函数
|
|||
svr.set_open_handler(OnOpen); |
|||
svr.set_close_handler(OnClose); |
|||
auto msg_handler = std::bind(OnMessage, &svr, std::placeholders::_1, |
|||
std::placeholders::_2); |
|||
svr.set_message_handler(msg_handler); |
|||
// 设置消息处理回调
|
|||
ws_server.set_message_handler(bind(&on_message, &ws_server, ::_1, ::_2)); |
|||
|
|||
// 5.启用地址重用
|
|||
svr.set_reuse_addr(true); |
|||
// 监听端口
|
|||
ws_server.listen(8081); |
|||
|
|||
// 6.设置监听端口
|
|||
svr.listen(8081); |
|||
// 启动服务器
|
|||
ws_server.start_accept(); |
|||
|
|||
// 7.开始监听
|
|||
svr.start_accept(); |
|||
// 运行服务器
|
|||
ws_server.run(); |
|||
|
|||
// 8.启动服务器
|
|||
svr.run(); |
|||
|
|||
return 0; |
|||
} |
@ -1 +1,2 @@ |
|||
E:\DataFile\ProjectX\TalkingWeb\ConsoleApplication3\main.cpp|638753491610634226|/root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/||g++ -c -x c++ /root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/main.cpp -I /usr/include -g2 -gdwarf-2 -o "/root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/obj/x64/Debug/main.o" -Wall -Wswitch -W"no-deprecated-declarations" -W"empty-body" -Wconversion -W"return-type" -Wparentheses -W"no-format" -Wuninitialized -W"unreachable-code" -W"unused-function" -W"unused-value" -W"unused-variable" -O0 -fno-strict-aliasing -fno-omit-frame-pointer -fthreadsafe-statics -fexceptions -frtti -std=c++11 |
|||
E:\DataFile\ProjectX\TalkingWeb\ConsoleApplication3\connMysql.cpp|638753935932534154|/root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/||g++ -c -x c++ /root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/connMysql.cpp -I /usr/include -I /usr/include/websocketpp -I /usr/include/nlohmann -g2 -gdwarf-2 -o "/root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/obj/x64/Debug/connMysql.o" -Wall -Wswitch -W"no-deprecated-declarations" -W"empty-body" -Wconversion -W"return-type" -Wparentheses -W"no-format" -Wuninitialized -W"unreachable-code" -W"unused-function" -W"unused-value" -W"unused-variable" -O0 -fno-strict-aliasing -fno-omit-frame-pointer -fthreadsafe-statics -fexceptions -frtti -std=c++11 |
|||
E:\DataFile\ProjectX\TalkingWeb\ConsoleApplication3\main.cpp|638753951995795770|/root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/||g++ -c -x c++ /root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/main.cpp -I /usr/include -I /usr/include/websocketpp -I /usr/include/nlohmann -g2 -gdwarf-2 -o "/root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/obj/x64/Debug/main.o" -Wall -Wswitch -W"no-deprecated-declarations" -W"empty-body" -Wconversion -W"return-type" -Wparentheses -W"no-format" -Wuninitialized -W"unreachable-code" -W"unused-function" -W"unused-value" -W"unused-variable" -O0 -fno-strict-aliasing -fno-omit-frame-pointer -fthreadsafe-statics -fexceptions -frtti -std=c++11 |
|||
|
@ -1 +1,2 @@ |
|||
E:\DataFile\ProjectX\TalkingWeb\ConsoleApplication3\main.cpp|638753491610634226|/root/ProjectCpp//root/ProjectCpp/ConsoleApplication3/| |
|||
E:\DataFile\ProjectX\TalkingWeb\ConsoleApplication3\connMysql.cpp|638753935932534154|/root/ProjectCpp//root/ProjectCpp/ConsoleApplication3/| |
|||
E:\DataFile\ProjectX\TalkingWeb\ConsoleApplication3\main.cpp|638753951995795770|/root/ProjectCpp//root/ProjectCpp/ConsoleApplication3/| |
|||
|
@ -1 +1 @@ |
|||
cd /root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/; g++ -o "/root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/bin/x64/Debug/ConsoleApplication3.out" -Wl,--no-undefined -Wl,-L/usr/lib -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack /root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/obj/x64/Debug/main.o |
|||
cd /root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/; g++ -o "/root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/bin/x64/Debug/ConsoleApplication3.out" -Wl,--no-undefined -Wl,-L/usr/lib -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack /root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/obj/x64/Debug/connMysql.o /root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/obj/x64/Debug/main.o |
@ -1,4 +1,5 @@ |
|||
E:\DataFile\ProjectX\TalkingWeb\ConsoleApplication3\main.cpp|/root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/main.cpp |
|||
E:\DataFile\ProjectX\TalkingWeb\ConsoleApplication3\connMysql.cpp|/root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/connMysql.cpp |
|||
E:\DataFile\ProjectX\TalkingWeb\ConsoleApplication3|/root/ProjectCpp/root/ProjectCpp/ConsoleApplication3 |
|||
@E:\DataFile\ProjectX\TalkingWeb\ConsoleApplication3|@/root/ProjectCpp/root/ProjectCpp/ConsoleApplication3 |
|||
E:\DataFile\ProjectX\TalkingWeb\ConsoleApplication3\main.cpp|/root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/main.cpp |
|||
E:\DataFile\ProjectX\TalkingWeb\ConsoleApplication3\|/root/ProjectCpp/root/ProjectCpp/ConsoleApplication3/ |
|||
|
@ -1 +1,2 @@ |
|||
E:\DataFile\ProjectX\TalkingWeb\ConsoleApplication3\connMysql.cpp;E:\DataFile\ProjectX\TalkingWeb\ConsoleApplication3\obj\x64\Debug\connMysql.o |
|||
E:\DataFile\ProjectX\TalkingWeb\ConsoleApplication3\main.cpp;E:\DataFile\ProjectX\TalkingWeb\ConsoleApplication3\obj\x64\Debug\main.o |
|||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 5.3 MiB |
Before Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 5.2 MiB |
@ -1,4 +1,12 @@ |
|||
import { createApp } from 'vue' |
|||
import App from './App.vue' |
|||
import router from './router/index.js' |
|||
createApp(App).use(router).mount('#app') |
|||
|
|||
const app = createApp(App) |
|||
|
|||
// 初始化 WebSocket 并挂载到 Vue 实例
|
|||
const ws = new WebSocket('ws://localhost:8081') |
|||
app.config.globalProperties.$ws = ws |
|||
|
|||
app.use(router) |
|||
app.mount('#app') |
@ -1,245 +1,158 @@ |
|||
<template> |
|||
<div class="auth-container"> |
|||
<div class="auth-card"> |
|||
<div class="tabs"> |
|||
<button |
|||
:class="['tab', { active: isLogin }]" |
|||
@click="toggleForm(true)" |
|||
> |
|||
登录 |
|||
</button> |
|||
<button |
|||
:class="['tab', { active: !isLogin }]" |
|||
@click="toggleForm(false)" |
|||
> |
|||
注册 |
|||
</button> |
|||
</div> |
|||
|
|||
<div class="auth-container"> |
|||
<div class="auth-box"> |
|||
<div class="image-container" @click="toggleForm"> |
|||
<transition name="fade" mode="out-in"> |
|||
<img :key="currentImage" :src="currentImage" alt="Auth Image" /> |
|||
</transition> |
|||
</div> |
|||
<div class="form-container"> |
|||
<transition name="fade" mode="out-in"> |
|||
<h2 :key="isLogin ? '登录' : '注册'">{{ isLogin ? '登录' : '注册' }}</h2> |
|||
</transition> |
|||
<form @submit.prevent="handleSubmit"> |
|||
<div class="form-group"> |
|||
<label>用户名</label> |
|||
<input |
|||
v-model="form.username" |
|||
type="text" |
|||
required |
|||
placeholder="请输入用户名" |
|||
> |
|||
<span class="error" v-if="errors.username">{{ errors.username }}</span> |
|||
<label for="username">账号</label> |
|||
<input type="text" id="username" v-model="username" required /> |
|||
</div> |
|||
|
|||
<div class="form-group"> |
|||
<label>密码</label> |
|||
<input |
|||
v-model="form.password" |
|||
type="password" |
|||
required |
|||
placeholder="请输入密码" |
|||
> |
|||
<span class="error" v-if="errors.password">{{ errors.password }}</span> |
|||
<label for="password">密码</label> |
|||
<input type="password" id="password" v-model="password" required /> |
|||
</div> |
|||
|
|||
<div v-if="!isLogin" class="form-group"> |
|||
<label>确认密码</label> |
|||
<input |
|||
v-model="form.confirmPassword" |
|||
type="password" |
|||
required |
|||
placeholder="请再次输入密码" |
|||
> |
|||
<span class="error" v-if="errors.confirmPassword">{{ errors.confirmPassword }}</span> |
|||
<div class="button-group"> |
|||
<button type="submit" v-if="isLogin" class="login-button">登录</button> |
|||
<button type="submit" v-else class="register-button">注册</button> |
|||
</div> |
|||
|
|||
<button type="submit" class="submit-btn"> |
|||
{{ isLogin ? '登录' : '注册' }} |
|||
<span v-if="loading" class="loader"></span> |
|||
</button> |
|||
</form> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, reactive } from 'vue' |
|||
import { useRouter } from 'vue-router' |
|||
import axios from 'axios' |
|||
|
|||
const router = useRouter() |
|||
const isLogin = ref(true) |
|||
const loading = ref(false) |
|||
|
|||
const form = reactive({ |
|||
username: '', |
|||
password: '', |
|||
confirmPassword: '' |
|||
}) |
|||
|
|||
const errors = reactive({ |
|||
username: '', |
|||
password: '', |
|||
confirmPassword: '' |
|||
}) |
|||
|
|||
const validateForm = () => { |
|||
let isValid = true |
|||
|
|||
if (!form.username) { |
|||
errors.username = '用户名不能为空' |
|||
isValid = false |
|||
} else { |
|||
errors.username = '' |
|||
} |
|||
|
|||
if (!form.password) { |
|||
errors.password = '密码不能为空' |
|||
isValid = false |
|||
} else if (form.password.length < 6) { |
|||
errors.password = '密码至少6位' |
|||
isValid = false |
|||
} else { |
|||
errors.password = '' |
|||
} |
|||
|
|||
if (!isLogin.value) { |
|||
if (form.password !== form.confirmPassword) { |
|||
errors.confirmPassword = '两次密码不一致' |
|||
isValid = false |
|||
} else { |
|||
errors.confirmPassword = '' |
|||
} |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
username: '', |
|||
password: '', |
|||
isLogin: true, |
|||
loginImage: require('@/assets/login.png'), |
|||
registerImage: require('@/assets/register.jpg'), |
|||
}; |
|||
}, |
|||
computed: { |
|||
currentImage() { |
|||
return this.isLogin ? this.loginImage : this.registerImage; |
|||
} |
|||
|
|||
return isValid |
|||
} |
|||
|
|||
const handleSubmit = async () => { |
|||
if (!validateForm()) return |
|||
|
|||
loading.value = true |
|||
try { |
|||
const url = isLogin.value ? '/api/login' : '/api/register' |
|||
const response = await axios.post(url, { |
|||
username: form.username, |
|||
password: form.password |
|||
}) |
|||
|
|||
localStorage.setItem('authToken', response.data.token) |
|||
router.push('/dashboard') |
|||
} catch (error) { |
|||
alert(error.response?.data?.message || '请求失败') |
|||
} finally { |
|||
loading.value = false |
|||
}, |
|||
methods: { |
|||
handleSubmit() { |
|||
const data = { |
|||
username: this.username, |
|||
password: this.password, |
|||
action: this.isLogin ? 'login' : 'register', |
|||
}; |
|||
// 发送数据到WebSocket服务器 |
|||
this.$ws.send(JSON.stringify(data)); |
|||
// 跳转到成功页面 |
|||
this.$router.push({ name: 'SuccessView' }); |
|||
}, |
|||
toggleForm() { |
|||
this.isLogin = !this.isLogin; |
|||
this.username = ''; |
|||
this.password = ''; |
|||
} |
|||
} |
|||
|
|||
const toggleForm = (login) => { |
|||
isLogin.value = login |
|||
Object.keys(form).forEach(key => form[key] = '') |
|||
Object.keys(errors).forEach(key => errors[key] = '') |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.auth-container { |
|||
min-height: 100vh; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|||
} |
|||
|
|||
.auth-card { |
|||
background: white; |
|||
padding: 2rem; |
|||
border-radius: 15px; |
|||
box-shadow: 0 10px 30px rgba(0,0,0,0.1); |
|||
width: 100%; |
|||
max-width: 400px; |
|||
} |
|||
|
|||
.tabs { |
|||
display: flex; |
|||
margin-bottom: 2rem; |
|||
border-bottom: 2px solid #eee; |
|||
} |
|||
|
|||
.tab { |
|||
flex: 1; |
|||
padding: 1rem; |
|||
border: none; |
|||
background: none; |
|||
cursor: pointer; |
|||
font-size: 1.1rem; |
|||
transition: all 0.3s ease; |
|||
} |
|||
|
|||
.tab.active { |
|||
color: #6366f1; |
|||
border-bottom: 3px solid #6366f1; |
|||
} |
|||
|
|||
.form-group { |
|||
margin-bottom: 1.5rem; |
|||
} |
|||
|
|||
label { |
|||
display: block; |
|||
margin-bottom: 0.5rem; |
|||
color: #666; |
|||
} |
|||
|
|||
input { |
|||
width: 100%; |
|||
padding: 0.8rem; |
|||
border: 1px solid #ddd; |
|||
border-radius: 8px; |
|||
font-size: 1rem; |
|||
transition: border-color 0.3s ease; |
|||
} |
|||
|
|||
input:focus { |
|||
outline: none; |
|||
border-color: #6366f1; |
|||
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2); |
|||
} |
|||
|
|||
.error { |
|||
color: #ef4444; |
|||
font-size: 0.875rem; |
|||
margin-top: 0.25rem; |
|||
display: block; |
|||
} |
|||
|
|||
.submit-btn { |
|||
width: 100%; |
|||
padding: 1rem; |
|||
background: #6366f1; |
|||
color: white; |
|||
border: none; |
|||
border-radius: 8px; |
|||
font-size: 1rem; |
|||
cursor: pointer; |
|||
transition: background 0.3s ease; |
|||
position: relative; |
|||
} |
|||
|
|||
.submit-btn:hover { |
|||
background: #4f46e5; |
|||
} |
|||
|
|||
.loader { |
|||
display: inline-block; |
|||
width: 20px; |
|||
height: 20px; |
|||
border: 3px solid rgba(255,255,255,0.3); |
|||
border-radius: 50%; |
|||
border-top-color: #fff; |
|||
animation: spin 1s ease-in-out infinite; |
|||
position: absolute; |
|||
right: 1rem; |
|||
} |
|||
|
|||
@keyframes spin { |
|||
to { transform: rotate(360deg); } |
|||
} |
|||
</style> |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.auth-container { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
height: 100vh; |
|||
width: 100%; |
|||
background: linear-gradient(135deg, #a6c0fe, #f68084); |
|||
} |
|||
|
|||
.auth-box { |
|||
display: flex; |
|||
background: white; |
|||
padding: 2rem; |
|||
border-radius: 8px; |
|||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); |
|||
width: 800px; |
|||
height: 400px; |
|||
overflow: hidden; |
|||
position: relative; |
|||
} |
|||
|
|||
.image-container { |
|||
flex: 1; |
|||
position: relative; |
|||
cursor: pointer; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.image-container img { |
|||
width: 100%; |
|||
height: 100%; |
|||
object-fit: cover; |
|||
} |
|||
|
|||
.form-container { |
|||
flex: 1; |
|||
padding: 1rem; |
|||
} |
|||
|
|||
h2 { |
|||
text-align: center; |
|||
margin-bottom: 1.5rem; |
|||
} |
|||
|
|||
.form-group { |
|||
margin-bottom: 1rem; |
|||
} |
|||
|
|||
label { |
|||
display: block; |
|||
margin-bottom: 0.5rem; |
|||
} |
|||
|
|||
input { |
|||
width: 100%; |
|||
padding: 0.5rem; |
|||
border: 1px solid #ccc; |
|||
border-radius: 4px; |
|||
} |
|||
|
|||
.button-group { |
|||
display: flex; |
|||
justify-content: center; |
|||
margin-top: 1rem; |
|||
} |
|||
|
|||
.login-button, .register-button { |
|||
width: 45%; |
|||
padding: 0.75rem; |
|||
border: none; |
|||
border-radius: 4px; |
|||
background: #2575fc; |
|||
color: white; |
|||
cursor: pointer; |
|||
transition: background-color 0.3s ease; |
|||
} |
|||
|
|||
.login-button:hover, .register-button:hover { |
|||
background: #1a5bbf; |
|||
} |
|||
|
|||
.fade-enter-active, .fade-leave-active { |
|||
transition: opacity 0.5s ease; |
|||
} |
|||
|
|||
.fade-enter-from, .fade-leave-to { |
|||
opacity: 0; |
|||
} |
|||
</style> |
@ -1,85 +0,0 @@ |
|||
<template> |
|||
<div class="dashboard"> |
|||
<h1>欢迎回来, {{ userInfo.username }}!</h1> |
|||
<div class="user-info"> |
|||
<p>注册时间: {{ formatDate(userInfo.createdAt) }}</p> |
|||
<button @click="handleLogout" class="logout-btn">退出登录</button> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, onMounted } from 'vue' |
|||
import { useRouter } from 'vue-router' |
|||
import axios from 'axios' |
|||
|
|||
const router = useRouter() |
|||
const userInfo = ref({ |
|||
username: '', |
|||
createdAt: '' |
|||
}) |
|||
|
|||
const formatDate = (dateString) => { |
|||
return new Date(dateString).toLocaleDateString() |
|||
} |
|||
|
|||
const fetchUserData = async () => { |
|||
try { |
|||
const response = await axios.get('/api/user') |
|||
userInfo.value = response.data |
|||
} catch (error) { |
|||
alert('获取用户信息失败') |
|||
router.push('/') |
|||
} |
|||
} |
|||
|
|||
const handleLogout = () => { |
|||
localStorage.removeItem('authToken') |
|||
router.push('/') |
|||
} |
|||
|
|||
onMounted(() => { |
|||
if (!localStorage.getItem('authToken')) { |
|||
router.push('/') |
|||
} else { |
|||
fetchUserData() |
|||
} |
|||
}) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.dashboard { |
|||
max-width: 800px; |
|||
margin: 2rem auto; |
|||
padding: 2rem; |
|||
background: white; |
|||
border-radius: 15px; |
|||
box-shadow: 0 4px 6px rgba(0,0,0,0.1); |
|||
} |
|||
|
|||
h1 { |
|||
color: #6366f1; |
|||
margin-bottom: 1.5rem; |
|||
} |
|||
|
|||
.user-info { |
|||
padding: 1.5rem; |
|||
background: #f8f9fa; |
|||
border-radius: 10px; |
|||
} |
|||
|
|||
.logout-btn { |
|||
margin-top: 1rem; |
|||
padding: 0.5rem 1.5rem; |
|||
background: #ef4444; |
|||
color: white; |
|||
border: none; |
|||
border-radius: 6px; |
|||
cursor: pointer; |
|||
transition: background 0.3s ease; |
|||
} |
|||
|
|||
.logout-btn:hover { |
|||
background: #dc2626; |
|||
} |
|||
</style> |
@ -0,0 +1,60 @@ |
|||
<template> |
|||
<div class="success-container"> |
|||
<div class="success-box"> |
|||
<h2>操作成功</h2> |
|||
<p>您已成功登录/注册!</p> |
|||
<button @click="goBack">返回首页</button> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
methods: { |
|||
goBack() { |
|||
this.$router.push({ name: 'AuthView' }); |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.success-container { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
height: 100vh; |
|||
width: 100%; |
|||
background: linear-gradient(135deg, #a6c0fe, #f68084); |
|||
} |
|||
|
|||
.success-box { |
|||
background: white; |
|||
padding: 2rem; |
|||
border-radius: 8px; |
|||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); |
|||
width: 300px; |
|||
text-align: center; |
|||
} |
|||
|
|||
h2 { |
|||
margin-bottom: 1rem; |
|||
} |
|||
|
|||
p { |
|||
margin-bottom: 1.5rem; |
|||
} |
|||
|
|||
button { |
|||
padding: 0.5rem 1rem; |
|||
border: none; |
|||
border-radius: 4px; |
|||
background: #2575fc; |
|||
color: white; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
button:hover { |
|||
background: #1a5bbf; |
|||
} |
|||
</style> |
Loading…
Reference in new issue