integrated_traffic_vue/src/layout/header/index.vue

264 lines
6.6 KiB
Vue

<template>
<div class="header">
<div class="left">
<div class="logo" />
<div class="menu">
<ul>
<li @click="router.push({ path: '/large_screen_data_display' })">
<div class="title">BI</div>
</li>
<template v-for="(item, index) in MENU" :key="index">
<li
:class="{ active: item.model === menuStore.getModel }"
@click="switchMenu(item.model)"
>
<div class="title">{{ item.title }}</div>
</li>
</template>
</ul>
</div>
</div>
<div class="user">
<el-dropdown
trigger="click"
placement="bottom-end"
@command="dropdownCommand"
>
<div class="user_info">
<el-avatar :size="23" fit="fill" :src="data.avatar" />
<span>{{ userStore.getUserInfo.NAME }}</span>
<icon-down
theme="filled"
size="16"
fill="#a2c2d3"
:stroke-width="3"
/>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="modifyInformation">
修改信息
</el-dropdown-item>
<el-dropdown-item command="modifyAvatar">
修改头像
</el-dropdown-item>
<el-dropdown-item command="signOut">退出</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
<update-info
v-model:visible="data.userDialog.visible"
v-model:form="data.userDialog.form"
@get-data="fnGetInfo"
/>
<update-avatar
v-model:visible="data.avatarDialog.visible"
v-model:form="data.avatarDialog.form"
@get-data="fnGetInfo"
/>
</div>
</template>
<script setup>
import { reactive } from "vue";
import { useRouter } from "vue-router";
import { useMenuStore } from "@/pinia/menu";
import { useUserStore } from "@/pinia/user";
import { MENU } from "@/assets/js/constant";
import { getInfo, getUserInfo, logout } from "@/request/api";
import { getSpecialOperationsWarnAmount } from "@/request/special_operations";
import UpdateInfo from "./components/update_info.vue";
import UpdateAvatar from "./components/update_avatar.vue";
import { checkImgExists, addingPrefixToFile } from "@/assets/js/utils.js";
import { useWebSocket } from "@vueuse/core";
import { nanoid } from "nanoid";
import { ElNotification } from "element-plus";
defineOptions({
name: "LayoutHeader",
});
const FILE_URL = import.meta.env.VITE_FILE_URL;
const router = useRouter();
const menuStore = useMenuStore();
const userStore = useUserStore();
const data = reactive({
avatar: "",
userDialog: {
visible: false,
form: {},
},
avatarDialog: {
visible: false,
form: {},
},
});
const dropdownCommand = async (command) => {
if (command === "signOut") {
await fnSignOut();
}
if (command === "modifyInformation") {
await fnGetUserInfo();
}
if (command === "modifyAvatar") {
data.avatarDialog.visible = true;
data.avatarDialog.form.file = addingPrefixToFile([
{ FILEPATH: userStore.getUserInfo.userPhoto },
]);
}
};
const fnGetUserInfo = async () => {
const resData = await getUserInfo({
USER_ID: userStore.getUserInfo.USER_ID,
});
data.userDialog.visible = true;
data.userDialog.form = resData.pd;
};
const switchMenu = (model) => {
menuStore.setModel(model);
};
const fnInitWebSocket = () => {
const { send } = useWebSocket(
encodeURI(import.meta.env.VITE_ON_LINE_WEB_SOCKET_URL),
{
onMessage: (ws, event) => {
const data = JSON.parse(event.data);
if (data.type === "goOut") fnSignOut();
else if (data.type === "thegoout") fnSignOut();
},
}
);
send("[join]" + nanoid());
};
const fnGetInfo = async () => {
const resData = await getInfo();
try {
await checkImgExists(FILE_URL + resData.userPhoto);
data.avatar = FILE_URL + resData.userPhoto;
} catch {
data.avatar = new URL(
"../../assets/images/public/tx.png",
import.meta.url
).href;
}
userStore.setUserInfo({
...userStore.getUserInfo,
...resData,
});
fnInitWebSocket();
};
fnGetInfo();
const fnSignOut = async () => {
await logout();
userStore.$reset();
await router.replace("/login");
};
const fnSpecialOperationsWarnAmount = async () => {
const resData = await getSpecialOperationsWarnAmount();
if (resData.message) {
ElNotification({
title: "温馨提示",
dangerouslyUseHTMLString: true,
message: resData.message,
duration: 0,
type: "warning",
});
}
};
fnSpecialOperationsWarnAmount();
</script>
<style lang="scss" scoped>
.header {
background-image: url("/src/assets/images/public/headerbg.png");
background-repeat: no-repeat;
background-size: 660px 70px;
background-color: #030f2f;
border-bottom: 1px solid #1f3869;
position: relative;
.left {
display: flex;
align-items: center;
position: relative;
z-index: 99;
width: max-content;
.logo {
background-image: url("/src/assets/images/public/logo.png");
width: 500px;
height: 69px;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.menu {
ul {
display: flex;
li {
height: 40px;
line-height: 40px;
text-align: center;
cursor: pointer;
background-color: #051748;
position: relative;
box-shadow: rgba(23, 66, 130, 1) 0px 0px 30px inset;
color: #fff;
min-width: 100px;
border: 1px solid #283d6f;
list-style: none;
padding: 0 20px;
margin-right: 20px;
border-radius: 2px;
&.active {
background-image: url("/src/assets/images/public/tguang.png");
background-repeat: no-repeat;
background-size: 100% 100%;
border: 1px solid #2870bb;
}
.title {
padding-left: 3px;
font-size: 14px;
}
}
}
}
}
.user {
width: 500px;
height: 70px;
background-image: url("/src/assets/images/public/userbg.jpg");
background-repeat: no-repeat;
background-size: 100% 100%;
display: flex;
justify-content: flex-end;
align-items: center;
position: absolute;
right: 0;
top: -1px;
.el-dropdown {
margin-right: 55px;
cursor: pointer;
position: absolute;
z-index: 999;
}
.user_info {
display: flex;
align-items: center;
span:nth-child(2) {
color: #ece8e8;
margin-left: 10px;
margin-right: 10px;
}
}
}
}
</style>