Files
education/frontend/node_modules/.cache/vue-loader/6b983616c2f9f0cb8950aabd1c1c099d.json
T

1 line
11 KiB
JSON

{"remainingRequest":"C:\\Users\\Admin\\Desktop\\education\\frontend\\node_modules\\vue-loader\\lib\\index.js??vue-loader-options!C:\\Users\\Admin\\Desktop\\education\\frontend\\src\\layout\\components\\HeaderNotice\\index.vue?vue&type=script&lang=js","dependencies":[{"path":"C:\\Users\\Admin\\Desktop\\education\\frontend\\src\\layout\\components\\HeaderNotice\\index.vue","mtime":1787567871537},{"path":"C:\\Users\\Admin\\Desktop\\education\\frontend\\node_modules\\cache-loader\\dist\\cjs.js","mtime":1787309791955},{"path":"C:\\Users\\Admin\\Desktop\\education\\frontend\\node_modules\\babel-loader\\lib\\index.js","mtime":1787309793142},{"path":"C:\\Users\\Admin\\Desktop\\education\\frontend\\node_modules\\cache-loader\\dist\\cjs.js","mtime":1787309791955},{"path":"C:\\Users\\Admin\\Desktop\\education\\frontend\\node_modules\\vue-loader\\lib\\index.js","mtime":1787309793790}],"contextDependencies":[],"result":[{"type":"Buffer","data":"base64:Ly8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KDQppbXBvcnQgTm90aWNlRGV0YWlsVmlldyBmcm9tICcuL0RldGFpbFZpZXcnDQppbXBvcnQgeyBsaXN0Tm90aWNlVG9wLCBtYXJrTm90aWNlUmVhZCwgbWFya05vdGljZVJlYWRBbGwgfSBmcm9tICdAL2FwaS9zeXN0ZW0vbm90aWNlJw0KDQpleHBvcnQgZGVmYXVsdCB7DQogIG5hbWU6ICdIZWFkZXJOb3RpY2UnLA0KICBjb21wb25lbnRzOiB7IE5vdGljZURldGFpbFZpZXcgfSwNCiAgZGF0YSgpIHsNCiAgICByZXR1cm4gew0KICAgICAgbm90aWNlTGlzdDogW10sIC8vIOmAmuefpeWIl+ihqA0KICAgICAgdW5yZWFkQ291bnQ6IDAsIC8vIOacquivu+aVsOmHjw0KICAgICAgbm90aWNlTG9hZGluZzogZmFsc2UsIC8vIOWKoOi9veeKtuaAgQ0KICAgICAgbm90aWNlVmlzaWJsZTogZmFsc2UsIC8vIOW8ueWHuuWxguaYvuekuueKtuaAgQ0KICAgICAgbm90aWNlTGVhdmVUaW1lcjogbnVsbCAvLyDpvKDmoIfnprvlvIDorqHml7blmagNCiAgICB9DQogIH0sDQogIG1vdW50ZWQoKSB7DQogICAgdGhpcy5sb2FkTm90aWNlVG9wKCkNCiAgfSwNCiAgbWV0aG9kczogew0KICAgIC8vIOm8oOagh+enu+WFpemTg+mTm+WMuuWfnw0KICAgIG9uTm90aWNlRW50ZXIoKSB7DQogICAgICBjbGVhclRpbWVvdXQodGhpcy5ub3RpY2VMZWF2ZVRpbWVyKQ0KICAgICAgdGhpcy5ub3RpY2VWaXNpYmxlID0gdHJ1ZQ0KICAgICAgdGhpcy4kbmV4dFRpY2soKCkgPT4gew0KICAgICAgICBjb25zdCBwb3BwZXIgPSB0aGlzLiRyZWZzLm5vdGljZVBvcG92ZXIuJHJlZnMucG9wcGVyDQogICAgICAgIGlmIChwb3BwZXIgJiYgIXBvcHBlci5fbm90aWNlQm91bmQpIHsNCiAgICAgICAgICBwb3BwZXIuX25vdGljZUJvdW5kID0gdHJ1ZQ0KICAgICAgICAgIHBvcHBlci5hZGRFdmVudExpc3RlbmVyKCdtb3VzZWVudGVyJywgKCkgPT4gY2xlYXJUaW1lb3V0KHRoaXMubm90aWNlTGVhdmVUaW1lcikpDQogICAgICAgICAgcG9wcGVyLmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlbGVhdmUnLCAoKSA9PiB7DQogICAgICAgICAgICB0aGlzLm5vdGljZUxlYXZlVGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHsgdGhpcy5ub3RpY2VWaXNpYmxlID0gZmFsc2UgfSwgMTAwKQ0KICAgICAgICAgIH0pDQogICAgICAgIH0NCiAgICAgIH0pDQogICAgfSwNCiAgICAvLyDpvKDmoIfnprvlvIDpk4Ppk5vljLrln58NCiAgICBvbk5vdGljZUxlYXZlKCkgew0KICAgICAgdGhpcy5ub3RpY2VMZWF2ZVRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7IHRoaXMubm90aWNlVmlzaWJsZSA9IGZhbHNlIH0sIDE1MCkNCiAgICB9LA0KICAgIC8vIOWKoOi9vemhtumDqOWFrOWRiuWIl+ihqA0KICAgIGxvYWROb3RpY2VUb3AoKSB7DQogICAgICB0aGlzLm5vdGljZUxvYWRpbmcgPSB0cnVlDQogICAgICBsaXN0Tm90aWNlVG9wKCkudGhlbihyZXMgPT4gew0KICAgICAgICB0aGlzLm5vdGljZUxpc3QgPSByZXMuZGF0YSB8fCBbXQ0KICAgICAgICB0aGlzLnVucmVhZENvdW50ID0gcmVzLnVucmVhZENvdW50ICE9PSB1bmRlZmluZWQgPyByZXMudW5yZWFkQ291bnQgOiB0aGlzLm5vdGljZUxpc3QuZmlsdGVyKG4gPT4gIW4uaXNSZWFkKS5sZW5ndGgNCiAgICAgIH0pLmZpbmFsbHkoKCkgPT4gew0KICAgICAgICB0aGlzLm5vdGljZUxvYWRpbmcgPSBmYWxzZQ0KICAgICAgfSkNCiAgICB9LA0KICAgIC8vIOmihOiniOWFrOWRiuivpuaDhQ0KICAgIHByZXZpZXdOb3RpY2UoaXRlbSkgew0KICAgICAgaWYgKCFpdGVtLmlzUmVhZCkgew0KICAgICAgICBtYXJrTm90aWNlUmVhZChpdGVtLm5vdGljZUlkKS5jYXRjaCgoKSA9PiB7fSkNCiAgICAgICAgaXRlbS5pc1JlYWQgPSB0cnVlDQogICAgICAgIGNvbnN0IGlkeCA9IHRoaXMubm90aWNlTGlzdC5pbmRleE9mKGl0ZW0pDQogICAgICAgIGlmIChpZHggIT09IC0xKSB0aGlzLiRzZXQodGhpcy5ub3RpY2VMaXN0LCBpZHgsIHsgLi4uaXRlbSwgaXNSZWFkOiB0cnVlIH0pDQogICAgICAgIHRoaXMudW5yZWFkQ291bnQgPSBNYXRoLm1heCgwLCB0aGlzLnVucmVhZENvdW50IC0gMSkNCiAgICAgIH0NCiAgICAgIHRoaXMuJHJlZnMubm90aWNlVmlld1JlZi5vcGVuKGl0ZW0ubm90aWNlSWQpDQogICAgfSwNCiAgICAvLyDlhajpg6jlt7Lor7sNCiAgICBtYXJrQWxsUmVhZCgpIHsNCiAgICAgIGNvbnN0IGlkcyA9IHRoaXMubm90aWNlTGlzdC5tYXAobiA9PiBuLm5vdGljZUlkKS5qb2luKCcsJykNCiAgICAgIGlmICghaWRzKSByZXR1cm4NCiAgICAgIG1hcmtOb3RpY2VSZWFkQWxsKGlkcykuY2F0Y2goKCkgPT4ge30pDQogICAgICB0aGlzLm5vdGljZUxpc3QgPSB0aGlzLm5vdGljZUxpc3QubWFwKG4gPT4gKHsgLi4ubiwgaXNSZWFkOiB0cnVlIH0pKQ0KICAgICAgdGhpcy51bnJlYWRDb3VudCA9IDANCiAgICB9DQogIH0NCn0NCg=="},{"version":3,"sources":["index.vue"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"index.vue","sourceRoot":"src/layout/components/HeaderNotice","sourcesContent":["<template>\r\n <div>\r\n <el-popover ref=\"noticePopover\" placement=\"bottom-end\" width=\"320\" trigger=\"manual\" :value=\"noticeVisible\" popper-class=\"notice-popover\">\r\n <div class=\"notice-header\">\r\n <span class=\"notice-title\">通知公告</span>\r\n <span class=\"notice-mark-all\" @click=\"markAllRead\">全部已读</span>\r\n </div>\r\n <div v-if=\"noticeLoading\" class=\"notice-loading\"><i class=\"el-icon-loading\"></i> 加载中...</div>\r\n <div v-else-if=\"noticeList.length === 0\" class=\"notice-empty\"><i class=\"el-icon-inbox\"></i><br>暂无公告</div>\r\n <div v-else>\r\n <div v-for=\"item in noticeList\" :key=\"item.noticeId\" class=\"notice-item\" :class=\"{ 'is-read': item.isRead }\" @click=\"previewNotice(item)\">\r\n <el-tag size=\"mini\" :type=\"item.noticeType === '1' ? 'warning' : 'success'\" class=\"notice-tag\">\r\n {{ item.noticeType === '1' ? '通知' : '公告' }}\r\n </el-tag>\r\n <span class=\"notice-item-title\">{{ item.noticeTitle }}</span>\r\n <span class=\"notice-item-date\">{{ item.createTime }}</span>\r\n </div>\r\n </div>\r\n </el-popover>\r\n\r\n <div v-popover:noticePopover class=\"right-menu-item hover-effect notice-trigger\" @mouseenter=\"onNoticeEnter\" @mouseleave=\"onNoticeLeave\">\r\n <svg-icon icon-class=\"bell\" />\r\n <span v-if=\"unreadCount > 0\" class=\"notice-badge\">{{ unreadCount }}</span>\r\n </div>\r\n\r\n <notice-detail-view ref=\"noticeViewRef\" />\r\n </div>\r\n</template>\r\n\r\n<script>\r\nimport NoticeDetailView from './DetailView'\r\nimport { listNoticeTop, markNoticeRead, markNoticeReadAll } from '@/api/system/notice'\r\n\r\nexport default {\r\n name: 'HeaderNotice',\r\n components: { NoticeDetailView },\r\n data() {\r\n return {\r\n noticeList: [], // 通知列表\r\n unreadCount: 0, // 未读数量\r\n noticeLoading: false, // 加载状态\r\n noticeVisible: false, // 弹出层显示状态\r\n noticeLeaveTimer: null // 鼠标离开计时器\r\n }\r\n },\r\n mounted() {\r\n this.loadNoticeTop()\r\n },\r\n methods: {\r\n // 鼠标移入铃铛区域\r\n onNoticeEnter() {\r\n clearTimeout(this.noticeLeaveTimer)\r\n this.noticeVisible = true\r\n this.$nextTick(() => {\r\n const popper = this.$refs.noticePopover.$refs.popper\r\n if (popper && !popper._noticeBound) {\r\n popper._noticeBound = true\r\n popper.addEventListener('mouseenter', () => clearTimeout(this.noticeLeaveTimer))\r\n popper.addEventListener('mouseleave', () => {\r\n this.noticeLeaveTimer = setTimeout(() => { this.noticeVisible = false }, 100)\r\n })\r\n }\r\n })\r\n },\r\n // 鼠标离开铃铛区域\r\n onNoticeLeave() {\r\n this.noticeLeaveTimer = setTimeout(() => { this.noticeVisible = false }, 150)\r\n },\r\n // 加载顶部公告列表\r\n loadNoticeTop() {\r\n this.noticeLoading = true\r\n listNoticeTop().then(res => {\r\n this.noticeList = res.data || []\r\n this.unreadCount = res.unreadCount !== undefined ? res.unreadCount : this.noticeList.filter(n => !n.isRead).length\r\n }).finally(() => {\r\n this.noticeLoading = false\r\n })\r\n },\r\n // 预览公告详情\r\n previewNotice(item) {\r\n if (!item.isRead) {\r\n markNoticeRead(item.noticeId).catch(() => {})\r\n item.isRead = true\r\n const idx = this.noticeList.indexOf(item)\r\n if (idx !== -1) this.$set(this.noticeList, idx, { ...item, isRead: true })\r\n this.unreadCount = Math.max(0, this.unreadCount - 1)\r\n }\r\n this.$refs.noticeViewRef.open(item.noticeId)\r\n },\r\n // 全部已读\r\n markAllRead() {\r\n const ids = this.noticeList.map(n => n.noticeId).join(',')\r\n if (!ids) return\r\n markNoticeReadAll(ids).catch(() => {})\r\n this.noticeList = this.noticeList.map(n => ({ ...n, isRead: true }))\r\n this.unreadCount = 0\r\n }\r\n }\r\n}\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.notice-trigger {\r\n position: relative;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n /* 自身不强行限制尺寸,由父级 .icon-btn 控制圆框尺寸 */\r\n width: 100%;\r\n height: 100%;\r\n .svg-icon { width: 18px; height: 18px; color: #fff; }\r\n .notice-badge {\r\n position: absolute;\r\n top: 2px;\r\n right: 2px;\r\n background: linear-gradient(135deg, #ff5e5e, #f5222d);\r\n color: #fff;\r\n border-radius: 10px;\r\n font-size: 10px;\r\n height: 16px;\r\n line-height: 16px;\r\n padding: 0 4px;\r\n min-width: 16px;\r\n text-align: center;\r\n white-space: nowrap;\r\n pointer-events: none;\r\n font-weight: 600;\r\n box-shadow: 0 2px 6px rgba(245, 34, 45, 0.5);\r\n border: 1.5px solid #fff;\r\n transform: scale(0.92);\r\n transform-origin: top right;\r\n }\r\n}\r\n.notice-popover {\r\n padding: 0 !important;\r\n}\r\n.notice-popover .notice-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 10px 14px;\r\n background: #f7f9fb;\r\n border-bottom: 1px solid #eee;\r\n font-size: 13px;\r\n font-weight: 600;\r\n color: #333;\r\n}\r\n.notice-popover .notice-mark-all {\r\n font-size: 12px;\r\n color: #00875A;\r\n font-weight: normal;\r\n cursor: pointer;\r\n}\r\n.notice-popover .notice-mark-all:hover { color: #2b7cc1; }\r\n.notice-popover .notice-loading,\r\n.notice-popover .notice-empty {\r\n padding: 24px;\r\n text-align: center;\r\n color: #bbb;\r\n font-size: 12px;\r\n line-height: 1.8;\r\n}\r\n.notice-popover .notice-item {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 10px 14px;\r\n border-bottom: 1px solid #f5f5f5;\r\n cursor: pointer;\r\n transition: background 0.15s;\r\n}\r\n.notice-popover .notice-item:last-child { border-bottom: none; }\r\n.notice-popover .notice-item:hover { background: #f7f9fb; }\r\n.notice-popover .notice-item.is-read .notice-tag,\r\n.notice-popover .notice-item.is-read .notice-item-title,\r\n.notice-popover .notice-item.is-read .notice-item-date { opacity: 0.45; filter: grayscale(1); color: #999; }\r\n.notice-popover .notice-tag { flex-shrink: 0; }\r\n.notice-popover .notice-item-title {\r\n flex: 1;\r\n font-size: 12px;\r\n color: #333;\r\n overflow: hidden;\r\n white-space: nowrap;\r\n text-overflow: ellipsis;\r\n}\r\n.notice-popover .notice-item-date {\r\n flex-shrink: 0;\r\n font-size: 11px;\r\n color: #bbb;\r\n}\r\n</style>\r\n"]}]}