mirror of
https://github.com/pure-admin/vue-pure-admin.git
synced 2025-06-07 08:57:19 +08:00
feat: add headerNotice
This commit is contained in:
parent
aa8005a982
commit
bcf533af62
@ -5,6 +5,7 @@ import Hamburger from "./sidebar/hamBurger.vue";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import { storageSession } from "/@/utils/storage";
|
||||
import Breadcrumb from "./sidebar/breadCrumb.vue";
|
||||
import Notice from "./notice/index.vue";
|
||||
import { useAppStoreHook } from "/@/store/modules/app";
|
||||
import { unref, watch, getCurrentInstance } from "vue";
|
||||
import { deviceDetection } from "/@/utils/deviceDetection";
|
||||
@ -70,6 +71,8 @@ function translationEn() {
|
||||
<Breadcrumb class="breadcrumb-container" />
|
||||
|
||||
<div class="vertical-header-right">
|
||||
<!-- 通知 -->
|
||||
<Notice />
|
||||
<!-- 全屏 -->
|
||||
<screenfull v-show="!deviceDetection()" />
|
||||
<!-- 国际化 -->
|
||||
@ -156,6 +159,12 @@ function translationEn() {
|
||||
color: #000000d9;
|
||||
justify-content: flex-end;
|
||||
|
||||
:deep(.dropdown-badge) {
|
||||
&:hover {
|
||||
background: #f6f6f6;
|
||||
}
|
||||
}
|
||||
|
||||
.screen-full {
|
||||
cursor: pointer;
|
||||
|
||||
|
110
src/layout/components/notice/index.vue
Normal file
110
src/layout/components/notice/index.vue
Normal file
@ -0,0 +1,110 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import NoticeList from "./noticeList.vue";
|
||||
|
||||
const loading = ref(false);
|
||||
const activeName = ref("first");
|
||||
|
||||
function visibleChange(val) {
|
||||
if (loading.value) {
|
||||
loading.value = false;
|
||||
return;
|
||||
}
|
||||
if (!val) return; //防止加载完成后再次点击出现loading
|
||||
loading.value = true;
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
const noticeList = [
|
||||
{
|
||||
imgUrl:
|
||||
"https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png",
|
||||
title: "你收到了 12 份新周报",
|
||||
description: "一年前"
|
||||
},
|
||||
{
|
||||
imgUrl:
|
||||
"https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png",
|
||||
title: "你推荐的 前端高手 已通过第三轮面试",
|
||||
description: "一年前"
|
||||
},
|
||||
{
|
||||
imgUrl:
|
||||
"https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png",
|
||||
title: "这种模板可以区分多种通知类型",
|
||||
description: "一年前"
|
||||
}
|
||||
];
|
||||
const newsList = [];
|
||||
const agencyList = [];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-dropdown
|
||||
trigger="click"
|
||||
placement="bottom-end"
|
||||
@visible-change="visibleChange"
|
||||
>
|
||||
<span class="dropdown-badge">
|
||||
<el-badge :value="12" :max="99">
|
||||
<el-icon class="header-notice-icon"><bell /></el-icon>
|
||||
</el-badge>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-tabs
|
||||
v-model="activeName"
|
||||
v-loading="loading"
|
||||
class="dropdown-tabs"
|
||||
:style="{ width: '297px' }"
|
||||
>
|
||||
<el-tab-pane label="通知" name="first">
|
||||
<NoticeList :list="noticeList" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="消息" name="second">
|
||||
<NoticeList :list="newsList" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="代办" name="third">
|
||||
<NoticeList :list="agencyList" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dropdown-badge {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 48px;
|
||||
width: 60px;
|
||||
cursor: pointer;
|
||||
|
||||
.header-notice-icon {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-tabs {
|
||||
background-color: #fff;
|
||||
box-shadow: 0 2px 8px rgb(0 0 0 / 15%);
|
||||
border-radius: 4px;
|
||||
|
||||
:deep(.el-tabs__nav-scroll) {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__nav-wrap)::after {
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__content) {
|
||||
padding: 0 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
62
src/layout/components/notice/noticeItem.vue
Normal file
62
src/layout/components/notice/noticeItem.vue
Normal file
@ -0,0 +1,62 @@
|
||||
<script setup lang="ts">
|
||||
import { PropType } from "vue";
|
||||
import { noticeItemType } from "../../types";
|
||||
|
||||
const props = defineProps({
|
||||
noticeItem: {
|
||||
type: Object as PropType<noticeItemType>,
|
||||
default: () => {}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="notice-container">
|
||||
<el-avatar
|
||||
:size="30"
|
||||
:src="props.noticeItem.imgUrl"
|
||||
class="notice-container-avatar"
|
||||
></el-avatar>
|
||||
<div class="notice-container-text">
|
||||
<div class="container-text-title">{{ props.noticeItem.title }}</div>
|
||||
<div class="container-text-description">
|
||||
{{ props.noticeItem.description }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.notice-container {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
.notice-container-avatar {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.notice-container-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
flex: 1;
|
||||
|
||||
.container-text-title {
|
||||
margin-bottom: 4px;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.container-text-description {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
23
src/layout/components/notice/noticeList.vue
Normal file
23
src/layout/components/notice/noticeList.vue
Normal file
@ -0,0 +1,23 @@
|
||||
<script setup lang="ts">
|
||||
import { PropType } from "vue";
|
||||
import NoticeItem from "./noticeItem.vue";
|
||||
import { noticeItemType } from "../../types";
|
||||
|
||||
const props = defineProps({
|
||||
list: {
|
||||
type: Array as PropType<Array<noticeItemType>>,
|
||||
default: () => []
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="props.list.length">
|
||||
<NoticeItem
|
||||
v-for="(item, index) in props.list"
|
||||
:noticeItem="item"
|
||||
:key="index"
|
||||
></NoticeItem>
|
||||
</div>
|
||||
<el-empty v-else description="暂无数据"></el-empty>
|
||||
</template>
|
@ -9,6 +9,7 @@ import {
|
||||
} from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { emitter } from "/@/utils/mitt";
|
||||
import Notice from "../notice/index.vue";
|
||||
import { templateRef } from "@vueuse/core";
|
||||
import SidebarItem from "./sidebarItem.vue";
|
||||
import { algorithm } from "/@/utils/algorithm";
|
||||
@ -138,6 +139,8 @@ onMounted(() => {
|
||||
/>
|
||||
</el-menu>
|
||||
<div class="horizontal-header-right">
|
||||
<!-- 通知 -->
|
||||
<Notice />
|
||||
<!-- 全屏 -->
|
||||
<screenfull v-show="!deviceDetection()" />
|
||||
<!-- 国际化 -->
|
||||
|
@ -71,3 +71,9 @@ export type themeColorsType = {
|
||||
rgb: string;
|
||||
themeColor: string;
|
||||
};
|
||||
|
||||
export type noticeItemType = {
|
||||
imgUrl: string;
|
||||
title: string;
|
||||
description: string;
|
||||
};
|
||||
|
@ -36,7 +36,12 @@ import {
|
||||
ElDescriptions,
|
||||
ElDescriptionsItem,
|
||||
ElBacktop,
|
||||
ElSwitch
|
||||
ElSwitch,
|
||||
ElBadge,
|
||||
ElTabs,
|
||||
ElTabPane,
|
||||
ElAvatar,
|
||||
ElEmpty
|
||||
} from "element-plus";
|
||||
|
||||
// https://element-plus.org/zh-CN/component/icon.html
|
||||
@ -54,7 +59,8 @@ import {
|
||||
RefreshRight,
|
||||
ArrowDown,
|
||||
Close,
|
||||
CloseBold
|
||||
CloseBold,
|
||||
Bell
|
||||
} from "@element-plus/icons";
|
||||
|
||||
const components = [
|
||||
@ -93,7 +99,12 @@ const components = [
|
||||
ElDescriptions,
|
||||
ElDescriptionsItem,
|
||||
ElBacktop,
|
||||
ElSwitch
|
||||
ElSwitch,
|
||||
ElBadge,
|
||||
ElTabs,
|
||||
ElTabPane,
|
||||
ElAvatar,
|
||||
ElEmpty
|
||||
];
|
||||
// icon
|
||||
export const iconComponents = [
|
||||
@ -110,7 +121,8 @@ export const iconComponents = [
|
||||
RefreshRight,
|
||||
ArrowDown,
|
||||
Close,
|
||||
CloseBold
|
||||
CloseBold,
|
||||
Bell
|
||||
];
|
||||
|
||||
const plugins = [ElLoading];
|
||||
|
@ -212,6 +212,15 @@
|
||||
color: $subMenuActiveText;
|
||||
justify-content: flex-end;
|
||||
|
||||
.dropdown-badge {
|
||||
height: 62px;
|
||||
color: $subMenuActiveText;
|
||||
|
||||
&:hover {
|
||||
background: $menuHover;
|
||||
}
|
||||
}
|
||||
|
||||
.screen-full {
|
||||
cursor: pointer;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user