状态管理

This commit is contained in:
2025-11-11 20:34:58 +08:00
parent c20dd5955a
commit c752bfd3c2
11 changed files with 179 additions and 80 deletions
@@ -1,25 +1,24 @@
<script setup> <script setup>
import { onMounted, ref } from 'vue' import { onMounted, ref } from "vue";
import { Offcanvas } from 'bootstrap' import { Offcanvas } from "bootstrap";
const offcanvasTop = ref(null) const offcanvasTop = ref(null);
let ov let ov;
const alertType=ref() // 可选值:'success', 'warning', 'danger', 'info' const alertType = ref(); // 可选值:'success', 'warning', 'danger', 'info'
const alertText=ref() const alertText = ref();
let autoCloseTimeout let autoCloseTimeout;
onMounted(() => { onMounted(() => {
// 确保在组件挂载后初始化 // 确保在组件挂载后初始化
if (offcanvasTop.value) { if (offcanvasTop.value) {
ov = new Offcanvas(offcanvasTop.value,{ ov = new Offcanvas(offcanvasTop.value, {
backdrop: false, backdrop: false,
}) });
//ov.show(); //ov.show();
//console.log('Offcanvas initialized:', ov) //console.log('Offcanvas initialized:', ov)
} }
}) });
function showAlert(type, text, timeout = 5000, callback) {
function showAlert(type, text,timeout=5000) {
alertText.value = text; alertText.value = text;
alertType.value = type; alertType.value = type;
@@ -27,24 +26,22 @@ function showAlert(type, text,timeout=5000) {
if (ov) { if (ov) {
ov.hide(); ov.hide();
ov.show(); ov.show();
if(autoCloseTimeout) if (autoCloseTimeout) {
{
clearTimeout(autoCloseTimeout); clearTimeout(autoCloseTimeout);
} }
autoCloseTimeout=setTimeout(() => { autoCloseTimeout = setTimeout(() => {
//console.log("timeout"); //console.log("timeout");
ov.hide(); ov.hide();
}, timeout); if (typeof callback === "function") {
callback();
}
}, timeout);
} }
} }
defineExpose({ defineExpose({
showAlert showAlert,
}); });
</script> </script>
<style scoped> <style scoped>
+38 -33
View File
@@ -2,47 +2,52 @@
"appname": { "appname": {
"home": "Home", "home": "Home",
"login": "Login", "login": "Login",
"forgot_password":"Forgot Password", "forgot_password": "Forgot Password",
"register":"Register" "register": "Register"
}, },
"message": { "message": {
"hello": "Hello", "hello": "Hello",
"welcome": "Welcome", "welcome": "Welcome",
"dark_mode":"Enable dark mode", "dark_mode": "Enable dark mode",
"light_mode":"Enable light mode", "light_mode": "Enable light mode",
"login_or_register":"Login/Register", "login_or_register": "Login/Register",
"login_to_your_account":"Login to your account", "login_to_your_account": "Login to your account",
"your_email_address":"Your email address", "your_email_address": "Your email address",
"email_address":"Email address", "email_address": "Email address",
"user_name":"User name", "user_name": "User name",
"your_user_name":"Your user name", "your_user_name": "Your user name",
"password":"Password", "password": "Password",
"your_password":"Your password", "your_password": "Your password",
"i_forgot_password":"I forgot my password", "i_forgot_password": "I forgot my password",
"remember_me_on_this_device":"Remember me on this device", "remember_me_on_this_device": "Remember me on this device",
"dont_have_account_yet":"Don't have an account yet?", "dont_have_account_yet": "Don't have an account yet?",
"register_now":"Register now", "register_now": "Register now",
"show_password":"Show password", "show_password": "Show password",
"hidden_Password":"Hidden Password", "hidden_Password": "Hidden Password",
"please_enter_username_and_password":"Please enter username and password", "please_enter_username_and_password": "Please enter username and password",
"forgot_password":"Forgot Password", "forgot_password": "Forgot Password",
"enter_your_email_to_reset_password":"Enter your email address and your password will be reset and emailed to you.", "enter_your_email_to_reset_password": "Enter your email address and your password will be reset and emailed to you.",
"back_to_login":"Back to login", "enter_your_username_to_reset_password": "Enter your user name and your password will be reset and emailed to you.",
"please_enter_your_email":"Please enter your email", "back_to_login": "Back to login",
"this_not_email":"This is not an email address.", "please_enter_your_email": "Please enter your email",
"create_new_account":"Create new account", "please_enter_your_username": "Please enter your user name",
"already_have_an_account":"Already have an account?" "this_not_email": "This is not an email address.",
"create_new_account": "Create new account",
"already_have_an_account": "Already have an account?",
"network_err":"Network error",
"username_dup":"Duplicate username",
"registration_successful":"Registration successful!"
}, },
"button": { "button": {
"submit": "Submit", "submit": "Submit",
"cancel": "Cancel", "cancel": "Cancel",
"sign_in":"Sign In", "sign_in": "Sign In",
"send_me_new_password":"Send me new password" "send_me_new_password": "Send me new password"
}, },
"footer":{ "footer": {
"doc":"Documentation", "doc": "Documentation",
"license":"License", "license": "License",
"source_code":"Source Code", "source_code": "Source Code",
"copy":"Copyright © 2025 Operations. All rights reserved." "copy": "Copyright © 2025 Operations. All rights reserved."
} }
} }
+6 -1
View File
@@ -27,11 +27,16 @@
"please_enter_username_and_password": "请输入用户名和密码", "please_enter_username_and_password": "请输入用户名和密码",
"forgot_password": "忘记密码", "forgot_password": "忘记密码",
"enter_your_email_to_reset_password": "输入您的邮箱地址,您的密码将被重置并通过邮件发送给您。", "enter_your_email_to_reset_password": "输入您的邮箱地址,您的密码将被重置并通过邮件发送给您。",
"enter_your_username_to_reset_password": "输入您的用户名,您的密码将被重置并通过邮件发送给您。",
"back_to_login": "返回登录", "back_to_login": "返回登录",
"please_enter_your_email": "请输入您的邮箱", "please_enter_your_email": "请输入您的邮箱",
"please_enter_your_username": "请输入您的用户名",
"this_not_email": "这不是一个有效的邮箱地址。", "this_not_email": "这不是一个有效的邮箱地址。",
"create_new_account":"创建新账户", "create_new_account":"创建新账户",
"already_have_an_account":"已经有账户了?" "already_have_an_account":"已经有账户了?",
"network_err":"网络错误",
"username_dup":"用户名重复",
"registration_successful":"注册成功!"
}, },
"button": { "button": {
"submit": "提交", "submit": "提交",
+4
View File
@@ -2,6 +2,7 @@ import './assets/main.css'
import { createApp } from 'vue' import { createApp } from 'vue'
import { createI18n } from 'vue-i18n' import { createI18n } from 'vue-i18n'
import { createPinia } from 'pinia' // 1. 导入 createPinia
import App from './App.vue' import App from './App.vue'
import router from './router' import router from './router'
@@ -22,8 +23,11 @@ const i18n = createI18n({
} }
}) })
const pinia = createPinia()
const app = createApp(App) const app = createApp(App)
app.use(router) app.use(router)
app.use(i18n) app.use(i18n)
app.use(pinia)
app.mount('#app') app.mount('#app')
+5
View File
@@ -17,6 +17,11 @@ const router = createRouter({
// which is lazy-loaded when the route is visited. // which is lazy-loaded when the route is visited.
component: () => import("../views/AboutView.vue"), component: () => import("../views/AboutView.vue"),
}, },
{
path: "/test",
name: "test",
component: () => import("../views/test.vue"),
},
{ {
path: "/login", path: "/login",
name: "login", name: "login",
+26
View File
@@ -0,0 +1,26 @@
// stores/user.js
import { defineStore } from "pinia";
import { ref, computed } from "vue";
// 组合式 API 写法 (推荐)
export const useUserStore = defineStore("user", () => {
// 状态 (State)
const userInfo = ref(null);
const token = ref("");
const isLoggedIn = ref(false);
const logout = () => {
isLoggedIn.value = false;
};
const login = () => {
isLoggedIn.value = true;
};
return {
userInfo,
token,
isLoggedIn,
logout,
login,
};
});
+6 -1
View File
@@ -1,5 +1,9 @@
<script setup> <script setup>
import { my_network_func } from '@/my_network_func'; import { my_network_func } from '@/my_network_func';
import { useUserStore } from '@/stores/user'
const user = useUserStore()
function t(){ function t(){
console.log("test") console.log("test")
@@ -14,7 +18,8 @@ import { my_network_func } from '@/my_network_func';
<template> <template>
<main> <main>
111 1112
<button @click="t">222</button> <button @click="t">222</button>
{{ user.isLoggedIn }}
</main> </main>
</template> </template>
@@ -12,15 +12,15 @@ function resetPassword() {
// 在这里处理重置密码逻辑 // 在这里处理重置密码逻辑
const emailValue = email.value?.value const emailValue = email.value?.value
if (emailValue === undefined || emailValue.trim() === '') { if (emailValue === undefined || emailValue.trim() === '') {
mos.value?.showAlert('info', t('message.please_enter_your_email'), 5000) mos.value?.showAlert('info', t('message.please_enter_your_username'), 5000)
return
}
if (!myfuncs.isValidEmail(emailValue)) {
mos.value?.showAlert('warning', t('message.this_not_email'), 5000)
return return
} }
// if (!myfuncs.isValidEmail(emailValue)) {
// mos.value?.showAlert('warning', t('message.this_not_email'), 5000)
// return
// }
mos.value?.showAlert('warning', "功能未开发", 5000)
console.log('sending password reset to:', emailValue) console.log('sending password reset to:', emailValue)
} }
@@ -52,15 +52,15 @@ watch(locale, () => {
<div class="card-body"> <div class="card-body">
<h2 class="card-title text-center mb-4">{{ t('message.forgot_password') }}</h2> <h2 class="card-title text-center mb-4">{{ t('message.forgot_password') }}</h2>
<p class="text-secondary mb-4"> <p class="text-secondary mb-4">
{{ t('message.enter_your_email_to_reset_password') }} {{ t('message.enter_your_username_to_reset_password') }}
</p> </p>
<div class="mb-3"> <div class="mb-3">
<label class="form-label">{{ t('message.email_address') }}</label> <label class="form-label">{{ t('message.user_name') }}</label>
<input <input
ref="email" ref="email"
type="email" type="text"
class="form-control" class="form-control"
:placeholder="t('message.your_email_address')" :placeholder="t('message.your_user_name')"
/> />
</div> </div>
<div class="form-footer"> <div class="form-footer">
@@ -74,6 +74,7 @@ watch(locale, () => {
<input <input
ref="username" ref="username"
type="text" type="text"
maxlength="64"
class="form-control" class="form-control"
:placeholder="t('message.your_user_name')" :placeholder="t('message.your_user_name')"
autocomplete="off" autocomplete="off"
+47 -12
View File
@@ -1,5 +1,6 @@
<script setup> <script setup>
import { onMounted, watch, ref } from "vue"; import { onMounted, watch, ref } from "vue";
import { useRouter } from "vue-router";
import MyOffcanvas from "@/components/MyOffcanvas.vue"; import MyOffcanvas from "@/components/MyOffcanvas.vue";
import { myfuncs } from "@/myfunc.js"; import { myfuncs } from "@/myfunc.js";
import { my_network_func } from "@/my_network_func"; import { my_network_func } from "@/my_network_func";
@@ -11,6 +12,7 @@ const isShowPassword = ref(false);
const username = ref(); const username = ref();
const useremail = ref(); const useremail = ref();
const userpassword = ref(); const userpassword = ref();
const router = useRouter();
function functionupdataTitle() { function functionupdataTitle() {
document.title = "Operations." + t("appname.register"); document.title = "Operations." + t("appname.register");
@@ -28,17 +30,22 @@ function createAccount() {
useremail.value?.classList.remove("is-invalid"); useremail.value?.classList.remove("is-invalid");
userpassword.value?.classList.remove("is-invalid"); userpassword.value?.classList.remove("is-invalid");
if (!user || !email || !pass) { let isDataErr = false;
if (!user) {
username.value?.classList.add("is-invalid");
}
if (!email) {
useremail.value?.classList.add("is-invalid");
}
if (!pass) {
userpassword.value?.classList.add("is-invalid");
}
if (!user) {
isDataErr = true;
username.value?.classList.add("is-invalid");
}
if (!email) {
isDataErr = true;
useremail.value?.classList.add("is-invalid");
}
if (!pass) {
isDataErr = true;
userpassword.value?.classList.add("is-invalid");
}
if (isDataErr) {
mos.value?.showAlert( mos.value?.showAlert(
"info", "info",
t("message.please_enter_username_and_password"), t("message.please_enter_username_and_password"),
@@ -46,6 +53,9 @@ function createAccount() {
); );
return; return;
} }
//判断长度
if (!myfuncs.isValidEmail(email)) { if (!myfuncs.isValidEmail(email)) {
useremail.value?.classList.add("is-invalid"); useremail.value?.classList.add("is-invalid");
mos.value?.showAlert("warning", t("message.this_not_email"), 5000); mos.value?.showAlert("warning", t("message.this_not_email"), 5000);
@@ -64,8 +74,31 @@ function createAccount() {
useremail: useremail.value?.value, useremail: useremail.value?.value,
userpass: userpassword.value?.value, userpass: userpassword.value?.value,
}, },
(r)=>{ (r) => {
console.log(r) console.log(r);
switch (r.statusCode) {
case 200:
switch (r.data.err_code) {
case -4:
username.value?.classList.add("is-invalid");
mos.value?.showAlert("warning", t("message.username_dup"), 5000);
break;
case 0:
mos.value?.showAlert(
"success",
t("message.registration_successful"),
1000,
() => {
router.push("/login");
}
);
break;
}
break;
default:
mos.value?.showAlert("danger", t("message.network_err"), 5000);
break;
}
} }
); );
} }
@@ -103,6 +136,7 @@ watch(locale, () => {
<input <input
ref="username" ref="username"
type="text" type="text"
maxlength="64"
class="form-control" class="form-control"
:placeholder="t('message.your_user_name')" :placeholder="t('message.your_user_name')"
/> />
@@ -112,6 +146,7 @@ watch(locale, () => {
<input <input
ref="useremail" ref="useremail"
type="email" type="email"
maxlength="250"
class="form-control" class="form-control"
:placeholder="t('message.your_email_address')" :placeholder="t('message.your_email_address')"
/> />
+16
View File
@@ -0,0 +1,16 @@
<script setup>
import { useUserStore } from '@/stores/user'
const user = useUserStore()
function t(){
user.login();
}
</script>
<template>
test
<button @click="t">222</button>
{{ user.isLoggedIn }}
</template>