Browse Source

add:消息中心基础样式

zhangrenyuan/feature-20251104133449-现金管理二期
lihui 3 weeks ago
parent
commit
d3ddb8e759
  1. 92
      src/components/dialogs/MessageDialog.vue
  2. 4
      src/components/dialogs/changePassword.vue
  3. 235
      src/views/home.vue

92
src/components/dialogs/MessageDialog.vue

@ -0,0 +1,92 @@
<script setup>
import { ref, onMounted } from 'vue'
import API from '@/util/http.js' //
const emit = defineEmits(['close', 'update-dot'])
const dialogRef = ref(null)
//
const messages = ref([])
//
async function getMessages() {
try {
const res = await API({ url: '/getMessages', method: 'GET' })
if (res.code === 200) {
messages.value = res.data
//
const hasUnread = messages.value.some(msg => !msg.read)
// emit('update-dot', false)
}else {
// emit('update-dot', false)
}
} catch (e) {
emit('update-dot', false)
console.error('获取消息失败:', e)
}
}
onMounted(() => {
getMessages()
})
function closeDialog() {
emit('close')
}
</script>
<template>
<dialog class="message-dialog" open>
<div class="dialog-content">
<h3>消息中心</h3>
<div v-if="messages.length > 0">
<!-- <div
v-for="msg in messages"
:key="msg.id"
class="msg-item"
:class="{ unread: !msg.read }"
>
{{ msg.title }}
</div>-->
<div>
测试测试
</div>
</div>
<div v-else>测试测试</div>
<div class="dialog-footer">
<el-button type="primary" @click="closeDialog">关闭</el-button>
</div>
</div>
</dialog>
</template>
<style scoped>
.message-dialog {
border: none;
border-radius: 10px;
background: rgba(255, 255, 255, 0.96);
box-shadow: 0 0 20px rgba(0, 0, 0, 0.25);
width: 380px;
z-index: 99999;
}
.dialog-content {
padding: 20px;
}
.msg-item {
padding: 6px 0;
}
.msg-item.unread {
font-weight: bold;
color: #409eff;
}
.dialog-footer {
text-align: right;
margin-top: 20px;
}
::backdrop {
background-color: rgba(0, 0, 0, 0.4);
}
</style>

4
src/components/changePassword.vue → src/components/dialogs/changePassword.vue

@ -4,8 +4,8 @@
import {ref, reactive, computed, watch, onMounted} from 'vue'
import {CircleCloseFilled, SuccessFilled} from '@element-plus/icons-vue'
import {ElMessage} from "element-plus";
import API from '@/util/http'
import PasswordSuccess from './PasswordSuccess.vue';
import API from '@/util/http.js'
import PasswordSuccess from '../PasswordSuccess.vue';
import router from "@/router/index.js";
//

235
src/views/home.vue

@ -1,17 +1,19 @@
<script setup>
//
import { computed, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import {computed, ref} from 'vue'
import {useRoute, useRouter} from 'vue-router'
import {ElMessage} from 'element-plus'
import dmmn from '../assets/link.png'
import ChangePassword from '@/components/changePassword.vue'
import { useAdminStore } from '@/store'
import { storeToRefs } from 'pinia'
import { filterMenu, getRoutePath } from "@/utils/menuUtils.js";
import ChangePassword from '@/components/dialogs/changePassword.vue'
import {useAdminStore} from '@/store'
import {storeToRefs} from 'pinia'
import {filterMenu, getRoutePath} from "@/utils/menuUtils.js";
import {Bell} from '@element-plus/icons-vue'
import SettingsIcon from '@/assets/blue.png';
// 使import.meta.globSVG
const icons = import.meta.glob('@/assets/SvgIcons/*.svg', { eager: true })
const icons = import.meta.glob('@/assets/SvgIcons/*.svg', {eager: true})
// import from '@/assets/SvgIcons/workbench.svg'
// import from '@/assets/SvgIcons/activity.png'
@ -39,7 +41,7 @@ const getIconPath = (menuName) => {
`./SvgIcons/${englishName}.svg`,
`/src/assets/SvgIcons/${englishName}.svg`
]
// icons
for (const key of possibleKeys) {
if (icons[key]) {
@ -51,28 +53,28 @@ const getIconPath = (menuName) => {
}
// -----------------------------------
//
import API from '@/util/http.js' // HTTP
import API from '@/util/http.js'
import MessageDialog from "@/components/dialogs/MessageDialog.vue"; // HTTP
//
const refreshData = async () => {
try {
// durationshowclose×
ElMessage({ message: '数据刷新中,请稍候...', type: 'info' });
ElMessage({message: '数据刷新中,请稍候...', type: 'info'});
// Mysql
const response = await API({ url: '/Mysql', method: 'POST', data: {} });
const response = await API({url: '/Mysql', method: 'POST', data: {}});
if (response && response.code === 200) {
const currentRoute = route.fullPath;
router.replace('/blank'); //
setTimeout(() => {
router.replace(currentRoute); //
}, 10);
ElMessage.success('数据刷新成功');
} else {
ElMessage.error('数据刷新失败:' + (response?.msg || '未知错误'));
@ -91,7 +93,7 @@ const menuList = ref([])
//
const adminStore = useAdminStore()
// adminData menuTree
const { adminData, menuTree, flag } = storeToRefs(adminStore)
const {adminData, menuTree, flag} = storeToRefs(adminStore)
// ,menuTree
menuList.value = filterMenu(menuTree.value)
@ -151,6 +153,7 @@ const pwdRef = ref()
const openChangePassword = () => {
showPasswordDialog.value = true
}
//
function onPwdDialogClosed() {
// resetFields
@ -170,9 +173,20 @@ const toggleFlag = () => {
const newFlag = flag.value === 1 ? 0 : 1
adminStore.setFlag(newFlag)
ElMessage.success(newFlag === 1 ? '员工数据已隐藏' : '员工数据已显示')
console.log('flag',newFlag)
console.log('flag', newFlag)
}
//
// MessageDialog
const showMessageDialog = ref(false)
//
const openMessageDialog = () => {
showMessageDialog.value = true
}
//
const messageDot = ref(true)
</script>
<template>
@ -183,93 +197,105 @@ const toggleFlag = () => {
<div class="sidebar-container">
<el-aside class="sidebar-layout">
<div class="logo">
<img src="../assets/新logo.png" alt="logo" style="width: 9vh; height: 9vh" />
<img src="../assets/新logo.png" alt="logo" style="width: 9vh; height: 9vh"/>
</div>
<div class="menu-scroll-container">
<el-menu :router="true" :default-active="activeMenu" style="min-height: 80vh;border:none;">
<!-- 递归渲染菜单层级 -->
<template v-for="menu in menuList" :key="menu.id">
<!-- 有子菜单的父级菜单menuType=2 且存在children -->
<el-sub-menu v-if="menu.children && menu.children.length > 0" :index="menu.id.toString()">
<template #title>
<img
:src="getIconPath(menu.menuName)"
:alt="`${menu.menuName}图标`"
style="width: 4vh; height: 4vh; margin-right: 4px;"
>
<span>{{ menu.menuName }}</span>
</template>
<!-- 子菜单 -->
<template v-for="child in menu.children" :key="child.id">
<!-- 子菜单为叶子节点无children -->
<el-menu-item v-if="!child.children || child.children.length === 0" :index="getRoutePath(child)">
<el-icon style="margin-right: 4px;">
<Folder />
</el-icon>
<span>{{ child.menuName }}</span>
</el-menu-item>
<!-- 子菜单有下级 -->
<el-sub-menu v-else :index="child.id.toString()">
<template #title>
<el-menu :router="true" :default-active="activeMenu" style="min-height: 80vh;border:none;">
<!-- 递归渲染菜单层级 -->
<template v-for="menu in menuList" :key="menu.id">
<!-- 有子菜单的父级菜单menuType=2 且存在children -->
<el-sub-menu v-if="menu.children && menu.children.length > 0" :index="menu.id.toString()">
<template #title>
<img
:src="getIconPath(menu.menuName)"
:alt="`${menu.menuName}图标`"
style="width: 4vh; height: 4vh; margin-right: 4px;"
>
<span>{{ menu.menuName }}</span>
</template>
<!-- 子菜单 -->
<template v-for="child in menu.children" :key="child.id">
<!-- 子菜单为叶子节点无children -->
<el-menu-item v-if="!child.children || child.children.length === 0" :index="getRoutePath(child)">
<el-icon style="margin-right: 4px;">
<Folder />
</el-icon>
<Folder/>
</el-icon>
<span>{{ child.menuName }}</span>
</template>
<!-- 递归 下一级-->
<template v-for="grandChild in child.children" :key="grandChild.id">
<el-menu-item :index="getRoutePath(grandChild)">
</el-menu-item>
<!-- 子菜单有下级 -->
<el-sub-menu v-else :index="child.id.toString()">
<template #title>
<el-icon style="margin-right: 4px;">
<Folder />
</el-icon>
<span>{{ grandChild.menuName }}</span>
</el-menu-item>
</template>
</el-sub-menu>
</template>
</el-sub-menu>
<!-- 无子菜单的一级菜单 -->
<el-menu-item v-else :index="getRoutePath(menu)">
<img
:src="getIconPath(menu.menuName)"
:alt="`${menu.menuName}图标`"
style="width: 4vh; height: 4vh; margin-right: 4px;"
>
<span>{{ menu.menuName }}</span>
</el-menu-item>
</template>
</el-menu>
<Folder/>
</el-icon>
<span>{{ child.menuName }}</span>
</template>
<!-- 递归 下一级-->
<template v-for="grandChild in child.children" :key="grandChild.id">
<el-menu-item :index="getRoutePath(grandChild)">
<el-icon style="margin-right: 4px;">
<Folder/>
</el-icon>
<span>{{ grandChild.menuName }}</span>
</el-menu-item>
</template>
</el-sub-menu>
</template>
</el-sub-menu>
<!-- 无子菜单的一级菜单 -->
<el-menu-item v-else :index="getRoutePath(menu)">
<img
:src="getIconPath(menu.menuName)"
:alt="`${menu.menuName}图标`"
style="width: 4vh; height: 4vh; margin-right: 4px;"
>
<span>{{ menu.menuName }}</span>
</el-menu-item>
</template>
</el-menu>
</div>
<!-- 底部固定的设置中心 -->
<div class="settings-container">
<el-dropdown placement="top-start">
<div style="display: flex">
<!-- 底部固定的设置中心 -->
<div class="settings-container">
<el-dropdown placement="top-start">
<span class="el-dropdown-link">
<!-- 暂时使用静态路径确保设置图标正常显示 -->
<img src="@/assets/SvgIcons/设置.svg" alt="设置" style="width: 4vh; height: 4vh" />
<img src="@/assets/SvgIcons/设置.svg" alt="设置" style="width: 4vh; height: 4vh"/>
<span>设置中心</span>
<el-icon class="arrow-icon">
<ArrowUp />
<ArrowUp/>
</el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="refreshData()">数据刷新</el-dropdown-item>
<!-- 员工数据开关 -->
<el-dropdown-item @click="toggleFlag()">
{{ flag === 1 ? '显示员工数据' : '隐藏员工数据' }}
</el-dropdown-item>
<el-dropdown-item @click="message()">查看个人信息</el-dropdown-item>
<el-dropdown-item @click="openChangePassword">修改密码</el-dropdown-item>
<el-dropdown-item @click="logout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="refreshData()">数据刷新</el-dropdown-item>
<!-- 员工数据开关 -->
<el-dropdown-item @click="toggleFlag()">
{{ flag === 1 ? '显示员工数据' : '隐藏员工数据' }}
</el-dropdown-item>
<el-dropdown-item @click="message()">查看个人信息</el-dropdown-item>
<el-dropdown-item @click="openChangePassword">修改密码</el-dropdown-item>
<el-dropdown-item @click="logout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
<!-- 消息提示 -->
<div class="message-container">
<el-badge :is-dot="messageDot" class="item">
<el-icon @click="openMessageDialog" style="cursor: pointer;">
<Bell/>
</el-icon>
</el-badge>
</div>
</div>
</el-aside>
</div>
@ -314,8 +340,17 @@ const toggleFlag = () => {
<!-- 自定义密码修改弹窗组件 -->
<el-dialog v-model="showPasswordDialog" :center="true" width="470px" @closed="onPwdDialogClosed">
<ChangePassword ref="pwdRef" @confirm="showPasswordDialog = false" />
<ChangePassword ref="pwdRef" @confirm="showPasswordDialog = false"/>
</el-dialog>
<MessageDialog
v-if="showMessageDialog"
@close="showMessageDialog = false"
@update-dot="messageDot = $event"
/>
</div>
</template>
@ -353,15 +388,17 @@ const toggleFlag = () => {
/* 侧边栏容器 */
.sidebar-container {
flex-shrink: 0;
}
.logo {
display: flex;
align-items: center;
justify-content: center;
height: 12vh;
}
/* 中间可滚动菜单容器 */
.menu-scroll-container {
flex: 1;
@ -376,6 +413,12 @@ const toggleFlag = () => {
align-items: center; /* 垂直居中 */
}
.message-container {
padding: 10px 50px 10px 50px; /* 上,右, 下,左 */
display: flex;
align-items: center; /* 垂直居中 */
}
/* 调整下拉菜单的样式,确保它向上弹出 */
.el-dropdown-link:focus {
@ -383,12 +426,14 @@ const toggleFlag = () => {
outline: none;
text-decoration: none;
}
.el-dropdown-link {
display: flex;
align-items: center;
cursor: pointer;
gap:10px; /* 图标和文字左右间距 */
gap: 10px; /* 图标和文字左右间距 */
}
.sidebar-layout {
width: 15vw;
height: 100%;
@ -439,7 +484,6 @@ const toggleFlag = () => {
}
/* 确保el-menu撑满容器 */
.sidebar-layout .el-menu {
width: 100%;
@ -456,6 +500,7 @@ const toggleFlag = () => {
::v-deep(.el-menu-item:hover) {
background: #E5EBFE;
}
/* 子菜单展开时和背景同色 */
::v-deep(.el-sub-menu__title),
::v-deep(.el-menu-item) {
@ -470,7 +515,6 @@ const toggleFlag = () => {
}
/* 确保全局el-container适应容器 */
:deep(.el-container) {
/* vue3的深度选择器,用于覆盖element-plus的默认样式 */
@ -480,7 +524,6 @@ const toggleFlag = () => {
}
/* 为侧边栏和主内容区域添加滚动条样式 */
.menu-scroll-container,
.el-main {

Loading…
Cancel
Save