| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498 |
- <template>
- <header
- class="fixed w-full top-0 z-100 bg-white border-b border-[#f0f2f5] shadow-sm"
- >
- <div
- class="w-full mx-auto flex items-center justify-between px-10 pr-0 h-18"
- >
- <div class="flex items-center gap-2 cursor-pointer" @click="goHome">
- <img :src="logo" alt="logo" class="w-20 h-9" />
- <span class="text-[#02409b] text-[20px] font-bold border-l-2 pl-1"
- >DeepOil</span
- >
- </div>
- <nav class="hidden lg:flex flex-1 mx-4 ml-10 text-sm">
- <ul class="flex items-center gap-6 text-[#303133]">
- <li><a class="hover:text-[#409EFF] cursor-pointer">产品</a></li>
- <li><a class="hover:text-[#409EFF] cursor-pointer">解决方案</a></li>
- <li><a class="hover:text-[#409EFF] cursor-pointer">典型案例</a></li>
- <li><a class="hover:text-[#409EFF] cursor-pointer">平台服务</a></li>
- <li><a class="hover:text-[#409EFF] cursor-pointer">应用市场</a></li>
- <li><a class="hover:text-[#409EFF] cursor-pointer">开源社区</a></li>
- </ul>
- </nav>
- <div class="hidden lg:flex items-center gap-3 h-full">
- <!-- 消息中心 -->
- <el-dropdown trigger="click" placement="bottom-end">
- <div class="flex items-center gap-2 cursor-pointer pr-2">
- <Icon
- icon="mdi:bell"
- class="w-5 h-5 text-gray-600 hover:text-[#409EFF]"
- />
- <span class="text-sm text-gray-600">消息代办</span>
- </div>
- <template #dropdown>
- <el-dropdown-menu class="notification-dropdown">
- <div class="notification-tabs pl-2">
- <el-tabs v-model="activeTab" class="demo-tabs">
- <el-tab-pane label="消息中心" name="messages">
- <div class="tab-content">
- <!-- 消息中心内容 -->
- <div
- class="message-item"
- v-for="(item, index) in messages"
- :key="index"
- >
- <div class="message-icon">
- <Icon
- :icon="item.icon"
- class="w-5 h-5"
- :class="item.typeClass"
- />
- </div>
- <div class="message-text">
- <p class="message-title">{{ item.title }}</p>
- <p class="message-desc">{{ item.desc }}</p>
- <p class="message-time">{{ item.time }}</p>
- </div>
- </div>
- <div v-if="!messages.length" class="no-messages">
- 暂无新消息
- </div>
- </div>
- </el-tab-pane>
- <el-tab-pane label="待办任务" name="tasks">
- <div class="tab-content">
- <!-- 待办任务内容 -->
- <div
- class="task-item"
- v-for="(task, index) in tasks"
- :key="index"
- >
- <div class="task-info">
- <p class="task-title">{{ task.title }}</p>
- <p class="task-desc">{{ task.desc }}</p>
- <p class="task-time">截止时间: {{ task.dueTime }}</p>
- </div>
- <el-tag :type="task.priorityTag" size="small">{{
- task.priorityText
- }}</el-tag>
- </div>
- <div v-if="!tasks.length" class="no-tasks">
- 暂无待办任务
- </div>
- </div>
- </el-tab-pane>
- </el-tabs>
- </div>
- </el-dropdown-menu>
- </template>
- </el-dropdown>
- <template v-if="isLoggedIn">
- <el-dropdown @command="onUserCommand" trigger="click">
- <span class="flex items-center gap-2 cursor-pointer pr-2">
- <div class="avatar-wrapper">
- <img
- :src="userAvatar || person"
- alt="avatar"
- class="w-8 h-8 rounded-full avatar-image"
- />
- </div>
- <span class="text-sm text-[#303133]">{{ userName }}</span>
- </span>
- <template #dropdown>
- <el-dropdown-menu>
- <el-dropdown-item command="profile">
- <svg
- xmlns="http://www.w3.org/2000/svg"
- width="18"
- height="18"
- viewBox="0 0 16 16"
- >
- <g fill="none">
- <path
- fill="url(#SVG3BqCJdyi)"
- d="M11.5 8A1.5 1.5 0 0 1 13 9.5v.5c0 1.971-1.86 4-5 4s-5-2.029-5-4v-.5A1.5 1.5 0 0 1 4.5 8z"
- />
- <path
- fill="url(#SVGfKhxtenh)"
- d="M11.5 8A1.5 1.5 0 0 1 13 9.5v.5c0 1.971-1.86 4-5 4s-5-2.029-5-4v-.5A1.5 1.5 0 0 1 4.5 8z"
- />
- <path
- fill="url(#SVGJYCMTblH)"
- d="M8 1.5A2.75 2.75 0 1 1 8 7a2.75 2.75 0 0 1 0-5.5"
- />
- <defs>
- <linearGradient
- id="SVG3BqCJdyi"
- x1="5.378"
- x2="7.616"
- y1="8.798"
- y2="14.754"
- gradientUnits="userSpaceOnUse"
- >
- <stop offset=".125" stop-color="#9c6cfe" />
- <stop offset="1" stop-color="#7a41dc" />
- </linearGradient>
- <linearGradient
- id="SVGfKhxtenh"
- x1="8"
- x2="11.164"
- y1="7.286"
- y2="17.139"
- gradientUnits="userSpaceOnUse"
- >
- <stop stop-color="#885edb" stop-opacity="0" />
- <stop offset="1" stop-color="#e362f8" />
- </linearGradient>
- <linearGradient
- id="SVGJYCMTblH"
- x1="6.558"
- x2="9.361"
- y1="2.231"
- y2="6.707"
- gradientUnits="userSpaceOnUse"
- >
- <stop offset=".125" stop-color="#9c6cfe" />
- <stop offset="1" stop-color="#7a41dc" />
- </linearGradient>
- </defs>
- </g>
- </svg>
- <span class="pl-2">个人中心</span>
- </el-dropdown-item>
- <el-dropdown-item command="logout">
- <svg
- xmlns="http://www.w3.org/2000/svg"
- width="18"
- height="18"
- viewBox="0 0 24 24"
- >
- <g fill="none">
- <path
- fill="url(#SVG0pAmxd9w)"
- d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2"
- />
- <path
- fill="url(#SVGFnXqmeDt)"
- d="m15.53 8.47l-.084-.073a.75.75 0 0 0-.882-.007l-.094.08L12 10.939l-2.47-2.47l-.084-.072a.75.75 0 0 0-.882-.007l-.094.08l-.073.084a.75.75 0 0 0-.007.882l.08.094L10.939 12l-2.47 2.47l-.072.084a.75.75 0 0 0-.007.882l.08.094l.084.073a.75.75 0 0 0 .882.007l.094-.08L12 13.061l2.47 2.47l.084.072a.75.75 0 0 0 .882.007l.094-.08l.073-.084a.75.75 0 0 0 .007-.882l-.08-.094L13.061 12l2.47-2.47l.072-.084a.75.75 0 0 0 .007-.882z"
- />
- <defs>
- <linearGradient
- id="SVG0pAmxd9w"
- x1="5.125"
- x2="18.25"
- y1="3.25"
- y2="22.625"
- gradientUnits="userSpaceOnUse"
- >
- <stop stop-color="#f83f54" />
- <stop offset="1" stop-color="#ca2134" />
- </linearGradient>
- <linearGradient
- id="SVGFnXqmeDt"
- x1="8.685"
- x2="12.591"
- y1="12.332"
- y2="16.392"
- gradientUnits="userSpaceOnUse"
- >
- <stop stop-color="#fdfdfd" />
- <stop offset="1" stop-color="#fecbe6" />
- </linearGradient>
- </defs>
- </g>
- </svg>
- <span class="pl-2">退出登录</span>
- </el-dropdown-item>
- </el-dropdown-menu>
- </template>
- </el-dropdown>
- </template>
- <template v-else>
- <div
- class="bg-[#0050b3] hover:bg-[#0050b3]/90 text-white text-sm flex items-center justify-center cursor-pointer h-full px-10 py-4"
- @click="login"
- >
- 登录
- </div>
- </template>
- </div>
- <div class="lg:hidden">
- <el-button link @click="drawer = true">
- <i class="el-icon" />
- <Icon icon="fa:bars" class="icon" />
- </el-button>
- </div>
- </div>
- <el-drawer
- v-model="drawer"
- placement="right"
- size="80%"
- :with-header="false"
- >
- <div class="p-4 space-y-3">
- <ul class="flex flex-col gap-3 text-[#303133]">
- <li><a class="block py-2">产品</a></li>
- <li><a class="block py-2">解决方案</a></li>
- <li><a class="block py-2">典型案例</a></li>
- <li><a class="block py-2">平台服务</a></li>
- <li><a class="block py-2">应用市场</a></li>
- <li><a class="block py-2">开源社区</a></li>
- </ul>
- <div class="flex items-center gap-3 mt-3">
- <el-button type="primary" class="flex-1 bg-[#0050b3]!" @click="login"
- >登录</el-button
- >
- </div>
- </div>
- </el-drawer>
- </header>
- </template>
- <script setup lang="ts">
- import { Icon } from "@iconify/vue";
- import { ref, computed } from "vue";
- import { useRouter } from "vue-router";
- import logo from "@/assets/images/logo.png";
- import person from "@/assets/images/person.png";
- import { useUserStoreWithOut } from "@/stores/useUserStore";
- const userStore = useUserStoreWithOut();
- import {
- getAccessToken,
- getRefreshToken,
- removeToken,
- setToken,
- } from "@utils/auth";
- import { deleteUserCache } from "@hooks/useCache";
- // 新增消息中心状态
- const activeTab = ref("messages");
- const messages = ref([
- {
- title: "系统通知",
- desc: "您的账户已成功激活",
- time: "10分钟前",
- icon: "mdi:message-text-outline",
- typeClass: "text-blue-500",
- },
- {
- title: "安全提醒",
- desc: "检测到异地登录行为",
- time: "30分钟前",
- icon: "mdi:security",
- typeClass: "text-red-500",
- },
- {
- title: "更新提示",
- desc: "系统将于今晚进行维护升级",
- time: "1小时前",
- icon: "mdi:update",
- typeClass: "text-green-500",
- },
- ]);
- const tasks = ref([
- {
- title: "审批申请",
- desc: "部门采购申请等待您审批",
- dueTime: "今天 17:00",
- priorityText: "高",
- priorityTag: "danger",
- },
- {
- title: "项目汇报",
- desc: "月度项目进度报告待提交",
- dueTime: "明天",
- priorityText: "中",
- priorityTag: "warning",
- },
- {
- title: "会议安排",
- desc: "准备下周团队会议材料",
- dueTime: "后天",
- priorityText: "低",
- priorityTag: "info",
- },
- ]);
- const isLoggedIn = computed(
- () => !!userStore.isSetUser || !!userStore.user?.id,
- );
- const userAvatar = computed(() => userStore.user?.avatar || "");
- const userName = computed(() => userStore.user?.nickname || "");
- const router = useRouter();
- const drawer = ref(false);
- const goHome = () => {
- router.push({ path: "/" });
- };
- const login = () => {
- router.push({
- path: "/login",
- });
- };
- const onUserCommand = async (command: string) => {
- if (command === "logout") {
- // await userStore.loginOut();
- deleteUserCache(); // 删除用户缓存
- removeToken();
- window.location.reload();
- }
- };
- </script>
- <style scoped>
- .avatar-wrapper {
- position: relative;
- overflow: hidden;
- border-radius: 50%;
- }
- .avatar-wrapper::before {
- content: "";
- position: absolute;
- top: 0;
- left: -100%;
- width: 50%;
- height: 100%;
- background: linear-gradient(
- 90deg,
- rgba(255, 255, 255, 0) 0%,
- rgba(255, 255, 255, 0.8) 50%,
- rgba(255, 255, 255, 0) 100%
- );
- transform: skewX(-25deg);
- transition: none;
- z-index: 1;
- opacity: 0;
- }
- .avatar-wrapper:hover::before {
- animation: shine 0.5s ease-out;
- }
- @keyframes shine {
- 0% {
- left: -100%;
- opacity: 0;
- }
- 10% {
- opacity: 1;
- }
- 100% {
- left: 100%;
- opacity: 0;
- }
- }
- .notification-dropdown {
- width: 400px !important;
- max-height: 500px;
- overflow: hidden;
- }
- .notification-tabs .el-tabs__header {
- margin-bottom: 0;
- padding: 10px;
- background-color: #f8f9fa;
- }
- .tab-content {
- max-height: 400px;
- overflow-y: auto;
- padding: 10px;
- }
- .message-item {
- display: flex;
- align-items: flex-start;
- padding: 12px 8px;
- border-bottom: 1px solid #eee;
- }
- .message-item:last-child {
- border-bottom: none;
- }
- .message-icon {
- margin-right: 12px;
- display: flex;
- align-items: center;
- }
- .message-text {
- flex: 1;
- }
- .message-title {
- font-weight: 500;
- color: #303133;
- margin-bottom: 4px;
- }
- .message-desc {
- font-size: 13px;
- color: #909399;
- line-height: 1.4;
- margin-bottom: 4px;
- }
- .message-time {
- font-size: 12px;
- color: #c0c4cc;
- }
- .no-messages,
- .no-tasks {
- text-align: center;
- padding: 20px;
- color: #909399;
- font-style: italic;
- }
- .task-item {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 12px 8px;
- border-bottom: 1px solid #eee;
- }
- .task-item:last-child {
- border-bottom: none;
- }
- .task-info {
- flex: 1;
- }
- .task-title {
- font-weight: 500;
- color: #303133;
- margin-bottom: 4px;
- }
- .task-desc {
- font-size: 13px;
- color: #909399;
- line-height: 1.4;
- margin-bottom: 4px;
- }
- .task-time {
- font-size: 12px;
- color: #c0c4cc;
- }
- </style>
|