引如了pinia集中管理数据

This commit is contained in:
Xiaoyu 2025-02-11 15:52:41 +08:00
parent f7854c2462
commit 44fc686a0a
6 changed files with 227 additions and 13 deletions

View File

@ -1,6 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch } from "vue"; import { ref, watch } from "vue";
import { useRouter, useRoute } from "vue-router"; import { useRouter, useRoute } from "vue-router";
import { ElMessageBox } from 'element-plus';
import { useUserStore } from '../stores/user';
import { useSystemLogStore } from '../stores/systemLog';
import { import {
Menu as IconMenu, Menu as IconMenu,
Location, Location,
@ -17,6 +20,8 @@ const router = useRouter();
const route = useRoute(); const route = useRoute();
const isCollapse = ref(false); const isCollapse = ref(false);
const activeMenu = ref(route.path); // const activeMenu = ref(route.path); //
const userStore = useUserStore();
const systemLogStore = useSystemLogStore();
// //
watch( watch(
@ -29,6 +34,34 @@ watch(
const handleSelect = (key: string) => { const handleSelect = (key: string) => {
router.push(key); router.push(key);
}; };
// 退
const handleLogout = () => {
ElMessageBox.confirm(
'确认退出登录?',
'提示',
{
confirmButtonText: '退出',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
// 退
systemLogStore.addLog({
type: "用户操作",
user: userStore.username || '',
action: "退出系统",
ip: "192.168.1.100",
status: "成功",
detail: "用户退出登录"
});
// 退
userStore.logout();
router.push('/login');
}).catch(() => {
// 退
});
};
</script> </script>
<template> <template>
@ -112,7 +145,7 @@ const handleSelect = (key: string) => {
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item>个人信息</el-dropdown-item> <el-dropdown-item>个人信息</el-dropdown-item>
<el-dropdown-item>修改密码</el-dropdown-item> <el-dropdown-item>修改密码</el-dropdown-item>
<el-dropdown-item divided>退出登录</el-dropdown-item> <el-dropdown-item divided @click="handleLogout">退出登录</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>

63
src/stores/systemLog.ts Normal file
View File

@ -0,0 +1,63 @@
import { defineStore } from 'pinia'
interface LogEntry {
id: number;
type: string;
user: string;
action: string;
ip: string;
status: string;
detail: string;
createTime: string;
}
export const useSystemLogStore = defineStore('systemLog', {
state: () => ({
logs: [] as LogEntry[]
}),
actions: {
// 添加日志
addLog(log: Omit<LogEntry, 'id' | 'createTime'>) {
const newLog: LogEntry = {
...log,
id: Date.now(),
createTime: new Date().toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
}).replace(/\//g, '-')
};
this.logs.unshift(newLog);
this.saveLogs();
},
// 加载日志
loadLogs() {
const savedLogs = localStorage.getItem('systemLogs');
if (savedLogs) {
this.logs = JSON.parse(savedLogs);
}
},
// 保存日志到localStorage
saveLogs() {
localStorage.setItem('systemLogs', JSON.stringify(this.logs));
},
// 清空日志
clearLogs() {
this.logs = [];
this.saveLogs();
}
},
getters: {
getLogs: (state) => state.logs
}
})

44
src/stores/user.ts Normal file
View File

@ -0,0 +1,44 @@
import { defineStore } from 'pinia'
interface UserState {
token: string | null;
userInfo: {
username: string;
role: string;
} | null;
}
export const useUserStore = defineStore('user', {
state: (): UserState => ({
token: localStorage.getItem('token'),
userInfo: null
}),
actions: {
// 登录
async login(username: string, password: string) {
if (username === 'admin' && password === '123456') {
this.token = 'demo-token';
this.userInfo = {
username: 'admin',
role: '管理员'
};
localStorage.setItem('token', this.token);
return true;
}
return false;
},
// 退出登录
logout() {
this.token = null;
this.userInfo = null;
localStorage.removeItem('token');
}
},
getters: {
isLoggedIn: (state) => !!state.token,
username: (state) => state.userInfo?.username
}
})

View File

@ -1,22 +1,75 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive } from "vue"; import { ref, reactive } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { ElMessage } from "element-plus";
import { useUserStore } from '../../stores/user';
import { useSystemLogStore } from '../../stores/systemLog';
const router = useRouter(); const router = useRouter();
const userStore = useUserStore();
const systemLogStore = useSystemLogStore();
const loginForm = reactive({ const loginForm = reactive({
username: "", username: "",
password: "", password: "",
}); });
const loading = ref(false); //
const rules = {
username: [
{ required: true, message: "请输入用户名", trigger: "blur" }
],
password: [
{ required: true, message: "请输入密码", trigger: "blur" }
]
};
const handleLogin = async () => { const loading = ref(false);
const formRef = ref();
//
const getCurrentTime = () => {
return new Date().toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
}).replace(/\//g, '-');
};
const handleLogin = async (formEl: any) => {
if (!formEl) return;
loading.value = true; loading.value = true;
try { try {
// TODO: API await formEl.validate();
localStorage.setItem("token", "demo-token");
const success = await userStore.login(loginForm.username, loginForm.password);
if (success) {
//
systemLogStore.addLog({
type: "用户操作",
user: loginForm.username,
action: "登录系统",
ip: "192.168.1.100",
status: "成功",
detail: "用户登录成功"
});
router.push("/dashboard"); router.push("/dashboard");
} else {
//
systemLogStore.addLog({
type: "用户操作",
user: loginForm.username,
action: "登录系统",
ip: "192.168.1.100",
status: "失败",
detail: "用户名或密码错误"
});
ElMessage.error("用户名或密码错误");
}
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} finally { } finally {
@ -29,11 +82,20 @@ const handleLogin = async () => {
<div class="login-container"> <div class="login-container">
<el-card class="login-card"> <el-card class="login-card">
<h2>智慧湿地管理平台</h2> <h2>智慧湿地管理平台</h2>
<el-form :model="loginForm" label-width="0"> <el-form
<el-form-item> ref="formRef"
<el-input v-model="loginForm.username" placeholder="用户名" prefix-icon="User" /> :model="loginForm"
:rules="rules"
label-width="0"
>
<el-form-item prop="username">
<el-input
v-model="loginForm.username"
placeholder="用户名"
prefix-icon="User"
/>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item prop="password">
<el-input <el-input
v-model="loginForm.password" v-model="loginForm.password"
type="password" type="password"
@ -47,7 +109,7 @@ const handleLogin = async () => {
type="primary" type="primary"
:loading="loading" :loading="loading"
class="login-button" class="login-button"
@click="handleLogin" @click="handleLogin(formRef)"
> >
登录 登录
</el-button> </el-button>

View File

@ -3,5 +3,11 @@
"references": [ "references": [
{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" } { "path": "./tsconfig.node.json" }
] ],
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
} }

View File

@ -1,7 +1,13 @@
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue'
import path from 'path'
// https://vite.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [vue()], plugins: [vue()],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
}
}) })