Browse Source

修复当前用户和用户菜单

master
zhangjiming 5 months ago
parent
commit
8a50db4d5d
  1. 2
      src/router/index.ts
  2. 8
      src/stores/user.ts
  3. 408
      src/views/components/Header.vue
  4. 47
      src/views/components/Time.vue
  5. 2
      src/views/components/UpdatePwd.vue
  6. 2
      src/views/components/menu.ts
  7. 4
      src/views/expeRecord/components/ExpeDetail.vue
  8. 5
      src/views/login/index.vue
  9. 193
      src/views/login/index1.vue

2
src/router/index.ts

@ -90,7 +90,7 @@ router.beforeEach((to, from) => {
} }
if (to.name === "userManage") { if (to.name === "userManage") {
const userStore = useUserStore(); const userStore = useUserStore();
if (userStore.user?.role !== 1) {
if (userStore.currUser.role !== 1) {
return { name: "graphite" }; return { name: "graphite" };
} }
} }

8
src/stores/user.ts

@ -9,6 +9,10 @@ export const useUserStore = defineStore("user", () => {
user.value = usr; user.value = usr;
}; };
const currUser = computed(() => {
return user.value || (JSON.parse(sessionStorage.getItem("user") || "{}") as User);
});
const userList = ref<User[] | undefined>(); const userList = ref<User[] | undefined>();
const setUserList = (users: User[]) => { const setUserList = (users: User[]) => {
userList.value = users; userList.value = users;
@ -24,6 +28,6 @@ export const useUserStore = defineStore("user", () => {
userList.value || [] userList.value || []
); );
}); });
return { user, setUser, userList, setUserList, userIdMap };
return { currUser, setUser, userList, setUserList, userIdMap };
}); });

408
src/views/components/Header.vue

@ -1,203 +1,215 @@
<template> <template>
<div class="header">
<div class="header_logo">
<img :src="logo" class="logo"/>
<div>长春黄金研究院有限公司</div>
</div>
<div class="header_time">
{{ currentTime }}
</div>
<div class="header_user">
<img :src="AvatarSvg" width="20px" height="20px"/>
<div class="user_name" @click="onShowMenu">Admin</div>
<div class="user_opt" v-show="showUserMenu">
<div class="updatePwd" @click="onUpdatePwd">
<img :src="PwdSvg" style="width: 1.25rem; height: 1.25rem;" />
修改密码
</div>
<div class="login_out" @click="onLoginout">
<img :src="OutSvg" style="width: 1.25rem; height: 1.25rem;"/>
退出登录</div>
</div>
</div>
<OverlayModal :visible="updatePwdVisible">
<UpdatePwd @cancel="onCancelUpdate"></UpdatePwd>
</OverlayModal>
</div>
<div class="header">
<div class="header_logo">
<img :src="logo" class="logo" />
<div>长春黄金研究院有限公司</div>
</div>
<div class="header_time">
<Time></Time>
</div>
<div class="header_user">
<el-dropdown trigger="click">
<div class="flex items-center gap-2">
<img :src="AvatarSvg" width="20px" height="20px" />
<div class="user_name" @click="onShowMenu">{{ userStore.currUser.nickname }}</div>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>
<div class="flex items-center gap-4 pl-2 pr-4 py-4 border-b border-[#eee]" @click="onUpdatePwd">
<img :src="PwdSvg" class="w-6 h-6" />
<p class="text-lg">修改密码</p>
</div>
</el-dropdown-item>
<el-dropdown-item>
<div class="flex items-center gap-4 pl-2 pr-4 py-4" @click="onLogout">
<img :src="OutSvg" class="w-6 h-6" />
<p class="text-lg">退出登录</p>
</div>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
<OverlayModal :visible="updatePwdVisible">
<UpdatePwd @cancel="onCancelUpdate"></UpdatePwd>
</OverlayModal>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import logo from '@/assets/logo.svg'
import AvatarSvg from '@/assets/avatar.svg'
import OutSvg from '@/assets/out.svg'
import PwdSvg from '@/assets/pwd.svg'
import { ref, onMounted } from 'vue'
import OverlayModal from '@/components/OverlayModal.vue'
import UpdatePwd from '../components/UpdatePwd.vue'
import {eventBus} from '@/eventBus'
import { useRouter } from 'vue-router'
import { getFormattedDateTime } from '@/utils'
const router = useRouter()
const menuId = ref(0)
const time = getFormattedDateTime()
const showUserMenu = ref(false)
const currentTime = ref(time)
onMounted(()=>{
//
// eventBus.on('menuId', (value:number)=>{
// menuId.value = value
// })
})
const updatePwdVisible = ref(false)
const onUpdatePwd = () => {
updatePwdVisible.value = true;
}
const onLoginout = () => {
router.push('/login')
}
const onShowMenu = () => {
showUserMenu.value = !showUserMenu.value;
}
const onCancelUpdate = () => {
updatePwdVisible.value = false;
}
import logo from "@/assets/logo.svg";
import AvatarSvg from "@/assets/avatar.svg";
import OutSvg from "@/assets/out.svg";
import PwdSvg from "@/assets/pwd.svg";
import { ref, onMounted } from "vue";
import OverlayModal from "@/components/OverlayModal.vue";
import UpdatePwd from "../components/UpdatePwd.vue";
import { eventBus } from "@/eventBus";
import { useRouter } from "vue-router";
import { getFormattedDateTime } from "@/utils";
import Time from "./Time.vue";
import { useUserStore } from "@/stores/user";
const router = useRouter();
const userStore = useUserStore();
const menuId = ref(0);
const time = getFormattedDateTime();
const showUserMenu = ref(false);
const currentTime = ref(time);
onMounted(() => {
//
// eventBus.on('menuId', (value:number)=>{
// menuId.value = value
// })
});
const updatePwdVisible = ref(false);
const onUpdatePwd = () => {
updatePwdVisible.value = true;
};
const onLogout = () => {
sessionStorage.removeItem("token");
router.push("/login");
};
const onShowMenu = () => {
showUserMenu.value = !showUserMenu.value;
};
const onCancelUpdate = () => {
updatePwdVisible.value = false;
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@use "@/assets/style/mixin.scss" as *;
.header{
display: flex;
align-items: center;
background: #F6F6F6;
padding: 0 20px;
height: var(--headerHeight);
.header_logo{
display: flex;
font-size: 1.125rem;
align-items: center;
width: 21.875rem;
color: #8799AB;
gap: 5px;
padding-left: 1.5625rem;
.logo{
height:2.75rem;
width:2.625rem;
}
}
.header_time{
width: 11.875rem;
height: 2.5rem;
font-size: .875rem;
display: flex;
align-items: center;
margin-left: 54%;
background: white;
justify-content: center;
border-radius: 10px;
}
.header_ins{
display: flex;
align-items: center;
border-radius: 5px;
width: 13.875rem;
height: 2.5rem;
background: #FFFFFF;
}
.header_container{
margin-left: 3.125rem;
display: flex;
align-items: center;
border-radius: 5px;
width: 15.625rem;
height: 2.5rem;
background: #FFFFFF;
.waste_status{
padding:5px 5px;
width: 75%;
}
.waste_detail{
display: flex;
justify-content: flex-end;
width: 40%;
}
}
.header_user{
display: flex;
align-items: center;
justify-content: flex-end;
gap: 5px;
margin-left: .9375rem;
}
.user_name{
font-size: 1rem;
color: #393F46;
}
.user_opt{
width: 10rem;
height: 6.25rem;
position:absolute;
top:3rem;
background: #ffffff;
.updatePwd{
color: #323233;
font-size: 1.125rem;
display: flex;
justify-content: center;
margin-top: 1.5rem;
gap: 15px;
}
.login_out{
color: #323233;
font-size: 1.125rem;
display: flex;
justify-content: center;
margin-top: .5rem;
gap: 15px;
}
}
}
.circle {
width: .9375rem;
height: .9375rem;
background-color: green;
border-radius: 50%;
margin-left: .3125rem;
}
:deep(.van-dropdown-menu__bar){
background-color: #1871F8;
border-radius: 5px;
height: .1rem;
width: 2.875rem;
.van-ellipsis{
color:white;
}
}
:deep(.van-dropdown-item__content){
width: 4.75rem;
margin-left: 5.375rem;
}
.text_size{
font-size:1rem;
padding-right: 5px;
}
</style>
@use "@/assets/style/mixin.scss" as *;
.header {
display: flex;
align-items: center;
background: #f6f6f6;
padding: 0 20px;
height: var(--headerHeight);
.header_logo {
display: flex;
font-size: 1.125rem;
align-items: center;
width: 21.875rem;
color: #8799ab;
gap: 5px;
padding-left: 1.5625rem;
.logo {
height: 2.75rem;
width: 2.625rem;
}
}
.header_time {
min-width: 11.875rem;
height: 2.5rem;
// font-size: .875rem;
display: flex;
align-items: center;
margin-left: auto;
background: white;
justify-content: center;
border-radius: 10px;
}
.header_ins {
display: flex;
align-items: center;
border-radius: 5px;
width: 13.875rem;
height: 2.5rem;
background: #ffffff;
}
.header_container {
margin-left: 3.125rem;
display: flex;
align-items: center;
border-radius: 5px;
width: 15.625rem;
height: 2.5rem;
background: #ffffff;
.waste_status {
padding: 5px 5px;
width: 75%;
}
.waste_detail {
display: flex;
justify-content: flex-end;
width: 40%;
}
}
.header_user {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 5px;
margin-left: 0.9375rem;
}
.user_name {
font-size: 1rem;
color: #393f46;
}
.user_opt {
width: 10rem;
height: 6.25rem;
position: absolute;
top: 3rem;
background: #ffffff;
.updatePwd {
color: #323233;
font-size: 1.125rem;
display: flex;
justify-content: center;
margin-top: 1.5rem;
gap: 15px;
}
.login_out {
color: #323233;
font-size: 1.125rem;
display: flex;
justify-content: center;
margin-top: 0.5rem;
gap: 15px;
}
}
}
.circle {
width: 0.9375rem;
height: 0.9375rem;
background-color: green;
border-radius: 50%;
margin-left: 0.3125rem;
}
:deep(.van-dropdown-menu__bar) {
background-color: #1871f8;
border-radius: 5px;
height: 0.1rem;
width: 2.875rem;
.van-ellipsis {
color: white;
}
}
:deep(.van-dropdown-item__content) {
width: 4.75rem;
margin-left: 5.375rem;
}
.text_size {
font-size: 1rem;
padding-right: 5px;
}
</style>

47
src/views/components/Time.vue

@ -0,0 +1,47 @@
<template>
<div>
<!-- 显示格式化后的时间 -->
{{ formattedTime }}
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue'
import dayjs from 'dayjs'
// props
const props = defineProps<{
format?: string
}>()
// 'YYYY-MM-DD HH:mm'使
const format = ref(props.format || 'YYYY-MM-DD HH:mm')
//
const formattedTime = ref('')
//
const updateClock = () => {
formattedTime.value = dayjs().format(format.value)
}
//
onMounted(() => {
updateClock() //
const intervalId = setInterval(updateClock, 1000) //
onUnmounted(() => clearInterval(intervalId)) //
})
//
watch(
() => props.format,
(newFormat) => {
format.value = newFormat || 'HH:mm' //
updateClock() //
},
)
</script>
<style scoped>
</style>

2
src/views/components/UpdatePwd.vue

@ -105,7 +105,7 @@
align-items: center; align-items: center;
border-radius: 10px; border-radius: 10px;
margin-left: 0.5rem; margin-left: 0.5rem;
border: 3px solid #1989FA;
border: 1px solid #1989FA;
color: #1989FA; color: #1989FA;
} }
} }

2
src/views/components/menu.ts

@ -94,7 +94,7 @@ const menuIcon = [
const userStore = useUserStore(); const userStore = useUserStore();
export function getMenus() { export function getMenus() {
if (userStore.user && userStore.user.role === 1) {
if (userStore.currUser.role === 1) {
return menuIcon; return menuIcon;
} else { } else {
return menuIcon.filter(m => m.path !== "/userManage"); return menuIcon.filter(m => m.path !== "/userManage");

4
src/views/expeRecord/components/ExpeDetail.vue

@ -10,8 +10,8 @@
v-for="step in record.steps" v-for="step in record.steps"
:key="step.id" :key="step.id"
class="h-10 flex items-center text-xs pr-3 text-[#6e6e6e] border-b border-b-[#f8f8f8]"> class="h-10 flex items-center text-xs pr-3 text-[#6e6e6e] border-b border-b-[#f8f8f8]">
<p class="w-[10rem]">{{ record.startTime }}</p>
<p>{{ record.name }}</p>
<p class="w-[10rem]">{{ step.startTime }}</p>
<p>{{ step.stepDescription }}</p>
</div> </div>
</main> </main>

5
src/views/login/index.vue

@ -62,11 +62,11 @@ const formRef = ref();
const rules = { const rules = {
username: [ username: [
{ required: true, message: "请输入用户名", trigger: "blur" }, { required: true, message: "请输入用户名", trigger: "blur" },
{ min: 3, max: 10, message: "长度在 3 到 10 个字符", trigger: "blur" },
{ min: 3, max: 20, message: "长度在 3 到 20 个字符", trigger: "blur" },
], ],
password: [ password: [
{ required: true, message: "请输入密码", trigger: "blur" }, { required: true, message: "请输入密码", trigger: "blur" },
{ min: 3, max: 10, message: "长度在 3 到 10 个字符", trigger: "blur" },
{ min: 3, max: 20, message: "长度在 3 到 20 个字符", trigger: "blur" },
] ]
} }
@ -87,6 +87,7 @@ const loginHandle = () => {
if (response.success) { if (response.success) {
const { username, nickname, role } = response.data; const { username, nickname, role } = response.data;
userStore.setUser({ username, nickname, role } as User); userStore.setUser({ username, nickname, role } as User);
sessionStorage.setItem("user", JSON.stringify({ username, nickname, role }))
} }
await router.push("/home"); await router.push("/home");
loading.value = false; loading.value = false;

193
src/views/login/index1.vue

@ -1,193 +0,0 @@
<template>
<div class="login-container">
<!-- 背景图 -->
<div class="background-image"></div>
<!-- 登录表单 -->
<div class="login-form">
<div class="login_logo">
<img :src="logoSvg" class="logo_size"/>
<div class="company_name">长春黄金研究院有限公司</div>
</div>
<el-form>
<el-form-item label="账号">
<el-input v-model="username" placehold="请输入用户名">
<template #prefix>
<img :src="userIconSvg" class="icon" alt=""/>
</template>
</el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="password" placehold="请输入密码">
<template #prefix>
<img :src="pwdIconSvg" class="icon" alt=""/>
</template>
</el-input>
</el-form-item>
</el-form>
<!-- 用户名输入框 -->
<!-- <div class="login-user-input">-->
<!-- <div class="user_name">用户名</div>-->
<!-- <img class="user_name_icon" :src="userIconSvg"/>-->
<!-- <input type="text" v-model="username" placeholder="用户名" class="input-field" />-->
<!-- </div>-->
<!-- &lt;!&ndash; 密码输入框 &ndash;&gt;-->
<!-- <div class="login-pwd-input">-->
<!-- <div class="user_name">密码</div>-->
<!-- <img class="pwd_icon" :src="pwdIconSvg"/>-->
<!-- <input type="password" v-model="password" placeholder="密码" class="input-field" />-->
<!-- </div>-->
<!-- 登录按钮 -->
<button @click="handleLogin" class="login-button">登录</button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { useRouter } from "vue-router";
import { showToast } from "vant";
import logoSvg from '@/assets/logo.svg'
import userIconSvg from '@/assets/user_icon.svg'
import pwdIconSvg from '@/assets/pwdw_icon.svg'
import { getCurrentUser, login, type User } from "@/services/user/userManager";
import { useUserStore } from "@/stores/user";
const router = useRouter();
//
const username = ref("");
const password = ref("");
const userStore = useUserStore();
//
const handleLogin = async () => {
if(!username.value || !password.value){
showToast('请输入用户名或密码!');
return;
}
const res = await login({ username: username.value, password: password.value });
if (res.success) {
sessionStorage.setItem("token", res.data);
const response = await getCurrentUser();
if (response.success) {
const { username, nickname, role } = response.data;
userStore.setUser({ username, nickname, role } as User);
}
router.push("/home");
} else {
showToast(res.msg);
}
};
</script>
<style lang="scss" scoped>
@use "@/assets/style/mixin.scss" as *;
.icon {
width: 20px;
}
.login-container {
position: relative;
width: 100vw;
height: 100vh;
overflow: hidden;
background: linear-gradient(180deg, rgba(250, 252, 255, 0.51) 0%, rgba(255, 255, 255, 0.52) 100%);
.login_logo{
.logo_size{
width: 2.875rem;
height: 2.875rem;
margin-top:2.875rem;
margin-left: 12rem;
}
.company_name{
color: #8799AB;
font-size: 1.25rem;
margin-top:1.5rem;
}
}
}
.background-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url('https://via.placeholder.com/1920x1080'); /* 替换为你自己的背景图 URL */
background-size: cover;
background-position: center;
filter: blur(5px);
z-index: -1;
}
.login-form {
position: absolute;
top: 50%;
left: 50%;
width:27.125rem;
transform: translate(-50%, -50%);
background-color: rgba(255, 255, 255, 0.8);
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
text-align: center;
}
.input-field {
width:19.75rem;
height: 2.75rem;
border: 1px solid #ccc;
border-radius: 5px;
margin-left: 3.625rem;
padding-left: 1.625rem;
}
.login-button {
width: 19.75rem;
height: 3rem;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
margin-top: 2rem;
margin-left: 2rem;
}
.login-button:hover {
background-color: #0056b3;
}
.login-user-input{
width: 10.2rem;
margin-top: 3rem;
.user_name{
color: #2C3E59;
font-size: 1rem;
}
.user_name_icon{
position: absolute;
margin-left: 4rem;
margin-top: 0.85rem;
width: 1.25rem;
height: 1.25rem;
}
}
.login-pwd-input{
width: 9.6rem;
margin-top: 2rem;
.pwd_icon{
position: absolute;
margin-left: 4rem;
margin-top: 0.75rem;
width: 1.25rem;
height: 1.25rem;
}
}
</style>
Loading…
Cancel
Save