|
@@ -0,0 +1,521 @@
|
|
|
+<!--
|
|
|
+ * @Author: zhangyu <taohuzy@163.com>
|
|
|
+ -->
|
|
|
+<template>
|
|
|
+ <div class="notification-box" v-clickOutside="handleClose" @click="handleClickRead">
|
|
|
+ <el-badge :value="unreadNum" :hidden="!unreadNum" :max="99">
|
|
|
+ <i class="el-icon-message-solid"></i>
|
|
|
+ </el-badge>
|
|
|
+ <transition name="el-fade-in-linear">
|
|
|
+ <div v-show="noticeListShow" @click.stop="" class="noticeBox">
|
|
|
+ <ul class="noticeTab">
|
|
|
+ <li class="noticeTab_item">
|
|
|
+ 消息通知
|
|
|
+ <!-- <span class="unread_num">1</span> -->
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ <div class="noticeList_scroll">
|
|
|
+ <el-scrollbar style="height: 100%">
|
|
|
+ <ul class="noticeList">
|
|
|
+ <li
|
|
|
+ class="noticeList_item"
|
|
|
+ v-for="item in messageList"
|
|
|
+ :key="item.id"
|
|
|
+ :title="item.content.message ? item.content.message : ''"
|
|
|
+ >
|
|
|
+ <div class="noticeItem_box">
|
|
|
+ <div class="noticeItem_text">
|
|
|
+ <i :class="iconClassMap[item.type] ? iconClassMap[item.type] : 'msg-icon el-icon-warning warning-color'"></i>
|
|
|
+ <p>
|
|
|
+ <span>{{ `【${moduleMap[item.module] ? moduleMap[item.module] : item.module}】 ` }}</span
|
|
|
+ >{{ item.title ? item.title : "" }}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <div class="noticeItem_time">
|
|
|
+ <span class="proname">{{ item.project[0].localName || "" }}</span>
|
|
|
+ {{ item.createTime }}
|
|
|
+ <template v-if="item.content.buttonList.length">
|
|
|
+ <el-link
|
|
|
+ v-for="(btn, index) in item.content.buttonList"
|
|
|
+ style="float: right; font-size: 12px; margin-left: 5px"
|
|
|
+ type="primary"
|
|
|
+ :key="index"
|
|
|
+ :href="`/image-service/common/file_get?systemId=revit&key=${btn.url}`"
|
|
|
+ :download="btn.fileName ? btn.fileName : ''"
|
|
|
+ >
|
|
|
+ {{ btn.name ? btn.name : "" }}
|
|
|
+ </el-link>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </el-scrollbar>
|
|
|
+ </div>
|
|
|
+ <div class="notice_operate">
|
|
|
+ <!-- <div class="readAll">全部标为已读</div> -->
|
|
|
+ <div class="seeAll" @click="allDetails">查看全部<i class="iconfont icon-right"></i></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </transition>
|
|
|
+ <!-- <el-button type="primary" @click="handleClickConnectMQ">连接MQ</el-button>
|
|
|
+ <el-button type="primary" @click="handleClickDisconnectMQ">断开MQ</el-button>
|
|
|
+ <el-button type="primary" @click="handleClickUnsubscribe">停止接收消息</el-button><br><br>
|
|
|
+ <el-input type="textarea" :autosize="{ minRows: 6, maxRows: 6}" v-model="sendMessage" placeholder="请输入要发送的内容"></el-input>
|
|
|
+ <br><br>
|
|
|
+ <el-button type="primary" @click="handleClickSendMessage">发送消息</el-button>
|
|
|
+ <el-card style="margin-top:20px;text-align:left;">
|
|
|
+ <div slot="header" class="clearfix">
|
|
|
+ <span>消息历史</span>
|
|
|
+ </div>
|
|
|
+ <div v-for="(message, index) in messageList" :key="index" class="text item">
|
|
|
+ {{ message }}
|
|
|
+ </div>
|
|
|
+ </el-card> -->
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts">
|
|
|
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
|
+// @ts-ignore
|
|
|
+import Stomp from "stompjs";
|
|
|
+import { Component, Vue } from "vue-property-decorator";
|
|
|
+import { UserModule } from "@/store/modules/user";
|
|
|
+import Msmq from "./msmq";
|
|
|
+import Bus from "@/utils/bus";
|
|
|
+import { MQTT_SERVICE, MQTT_USERNAME, MQTT_PASSWORD } from "./mqSetting";
|
|
|
+import { messgeCount, messgeQuery, messgeUpdateState } from "@/api/messagecenter";
|
|
|
+
|
|
|
+@Component({
|
|
|
+ name: "MessageSever",
|
|
|
+ components: {},
|
|
|
+})
|
|
|
+export default class extends Vue {
|
|
|
+ // STOMP客户端对象
|
|
|
+ private client = Stomp.client(MQTT_SERVICE);
|
|
|
+ // 未读消息数量
|
|
|
+ private unreadNum = 0;
|
|
|
+ // 消息列表是否显示标志
|
|
|
+ private noticeListShow = false;
|
|
|
+ // 发送的消息内容
|
|
|
+ private sendMessage = "";
|
|
|
+ // 历史消息
|
|
|
+ private messageList = [];
|
|
|
+ // 订阅的消息实例
|
|
|
+ private subList: any[] = [];
|
|
|
+ // 订阅的消息名称
|
|
|
+ private topics: string[] = ["/topic/message.manage"];
|
|
|
+ // 消息模块映射
|
|
|
+ private moduleMap = {
|
|
|
+ Model: "模型文件管理",
|
|
|
+ };
|
|
|
+ // 消息类型图标映射
|
|
|
+ private iconClassMap = {
|
|
|
+ Success: "msg-icon el-icon-success success-color",
|
|
|
+ Error: "msg-icon el-icon-error error-color",
|
|
|
+ Warning: "msg-icon el-icon-warning warning-color",
|
|
|
+ Info: "msg-icon el-icon-info info-color",
|
|
|
+ };
|
|
|
+
|
|
|
+ get userId(): string {
|
|
|
+ return UserModule.userId;
|
|
|
+ }
|
|
|
+
|
|
|
+ get username(): string {
|
|
|
+ return UserModule.username;
|
|
|
+ }
|
|
|
+
|
|
|
+ get projectId(): string {
|
|
|
+ return UserModule.projectId;
|
|
|
+ }
|
|
|
+
|
|
|
+ get projects(): any[] {
|
|
|
+ return UserModule.projects;
|
|
|
+ }
|
|
|
+
|
|
|
+ created() {
|
|
|
+ this.connect();
|
|
|
+ }
|
|
|
+ mounted() {
|
|
|
+ this.getUnreadCount();
|
|
|
+ this.getMessageList(); //获取消息列表
|
|
|
+ Bus.$on("messageListUpdate", () => {
|
|
|
+ this.getMessageList();
|
|
|
+ });
|
|
|
+ Bus.$on("getUnreadCountUpdate", () => {
|
|
|
+ this.getUnreadCount();
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取消息列表(最新10条)
|
|
|
+ */
|
|
|
+ private async getMessageList() {
|
|
|
+ const params = {
|
|
|
+ cascade: [
|
|
|
+ {
|
|
|
+ name: "project",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ filters: `userId='${this.userId}';type!='refresh'`,
|
|
|
+ orders: "createTime desc, id asc",
|
|
|
+ pageNumber: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ };
|
|
|
+ const res = await messgeQuery(params);
|
|
|
+ this.messageList = res.content || [];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取未读消息的数量
|
|
|
+ */
|
|
|
+ private async getUnreadCount() {
|
|
|
+ let params = {
|
|
|
+ filters: `read=false;userId='${this.userId}';type!='refresh'`,
|
|
|
+ };
|
|
|
+ const res = await messgeCount(params);
|
|
|
+ this.unreadNum = res.count || 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将当前角色消息全部置为已读
|
|
|
+ */
|
|
|
+ private async setAllRead() {
|
|
|
+ if (this.userId) {
|
|
|
+ const res = await messgeUpdateState({ read: true, userId: this.userId });
|
|
|
+ if (res.result === "success") this.unreadNum = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 关闭消息列表
|
|
|
+ */
|
|
|
+ handleClose(e: Event) {
|
|
|
+ this.noticeListShow = false;
|
|
|
+ return e;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 点击消息铃铛
|
|
|
+ */
|
|
|
+ private handleClickRead() {
|
|
|
+ this.noticeListShow ? (this.noticeListShow = false) : (this.noticeListShow = true);
|
|
|
+ if (this.noticeListShow) {
|
|
|
+ this.setAllRead(); //将当前角色消息全部置为已读
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 连接STOMP服务端
|
|
|
+ */
|
|
|
+ private connect() {
|
|
|
+ this.client = Stomp.client(MQTT_SERVICE);
|
|
|
+ this.client.reconnect_delay = 5000;
|
|
|
+ var clientid = `sagaMQ-${this.username}-${new Date().getTime()}`;
|
|
|
+ var headers = {
|
|
|
+ login: MQTT_USERNAME,
|
|
|
+ passcode: MQTT_PASSWORD,
|
|
|
+ "client-id": clientid,
|
|
|
+ };
|
|
|
+ this.client.connect(headers, this.onConnected, this.onFailed);
|
|
|
+ }
|
|
|
+
|
|
|
+ private onConnected(frame: any) {
|
|
|
+ console.log("Connected: " + frame);
|
|
|
+ //订阅多个消息
|
|
|
+ this.topics.forEach((item: string) => {
|
|
|
+ const sub: any = this.client.subscribe(item, this.onmessage, this.onFailed);
|
|
|
+ this.subList.push(sub);
|
|
|
+ });
|
|
|
+ // this.client.subscribe(topic, this.onmessage, this.onFailed)
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 接收到消息的回调
|
|
|
+ */
|
|
|
+ private onmessage(message: string) {
|
|
|
+ this.unreadNum = Msmq.handleMsg(message, this.projects, this.userId, this.unreadNum);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 接收消息失败回调
|
|
|
+ */
|
|
|
+ private onFailed(frame: any) {
|
|
|
+ console.log("Failed: " + frame);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 停止接收消息
|
|
|
+ */
|
|
|
+ private unsubscribe() {
|
|
|
+ this.subList.forEach((item: any) => {
|
|
|
+ item.unsubscribe();
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 断开连接
|
|
|
+ */
|
|
|
+ private disconnect() {
|
|
|
+ this.client.disconnect(function () {
|
|
|
+ console.log("连接已断开!");
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 发送消息
|
|
|
+ */
|
|
|
+ private send(destination: string, message: any, headers = {}) {
|
|
|
+ this.client.send(destination, headers, JSON.stringify(message));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 连接MQ
|
|
|
+ */
|
|
|
+ private handleClickConnectMQ() {
|
|
|
+ this.connect();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 断开MQ
|
|
|
+ */
|
|
|
+ private handleClickDisconnectMQ() {
|
|
|
+ this.disconnect();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 停止接收消息
|
|
|
+ */
|
|
|
+ private handleClickUnsubscribe() {
|
|
|
+ this.unsubscribe();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 发送消息
|
|
|
+ */
|
|
|
+ private handleClickSendMessage() {
|
|
|
+ this.send("/topic/datacenter.broadcast", this.sendMessage);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查看完整消息列表(跳转消息列表页面)
|
|
|
+ */
|
|
|
+ private allDetails() {
|
|
|
+ this.noticeListShow = false;
|
|
|
+ this.$router.push({ path: "/allDetails" });
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.notification-box {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ position: relative;
|
|
|
+ line-height: 1;
|
|
|
+ padding: 16px 10px 12px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ color: #79869a;
|
|
|
+ cursor: pointer;
|
|
|
+ .noticeBox {
|
|
|
+ position: absolute;
|
|
|
+ top: 50px;
|
|
|
+ left: 50%;
|
|
|
+ margin-left: -220px;
|
|
|
+ cursor: auto;
|
|
|
+ z-index: 1000;
|
|
|
+ text-align: left;
|
|
|
+ width: 272px;
|
|
|
+ height: 362px;
|
|
|
+ box-shadow: 0 1px 6px 0 #ccc;
|
|
|
+ color: #333;
|
|
|
+ background: #fff;
|
|
|
+ overflow: visible !important;
|
|
|
+ }
|
|
|
+ .noticeBox::before {
|
|
|
+ content: "";
|
|
|
+ border: solid 7px transparent;
|
|
|
+ border-bottom-color: #fff;
|
|
|
+ display: block;
|
|
|
+ position: absolute;
|
|
|
+ width: 2px;
|
|
|
+ top: -14px;
|
|
|
+ left: 50%;
|
|
|
+ margin-left: 77px;
|
|
|
+ z-index: 0;
|
|
|
+ }
|
|
|
+ .noticeTab {
|
|
|
+ padding: 8px 16px 0;
|
|
|
+ z-index: 10;
|
|
|
+ height: 40px;
|
|
|
+ zoom: 1;
|
|
|
+ box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.1) inset;
|
|
|
+ .noticeTab_item {
|
|
|
+ position: relative;
|
|
|
+ width: 240px;
|
|
|
+ height: 32px;
|
|
|
+ line-height: 32px;
|
|
|
+ padding: 0;
|
|
|
+ margin-right: 0;
|
|
|
+ font-weight: 700;
|
|
|
+ text-align: left;
|
|
|
+ cursor: pointer;
|
|
|
+ -webkit-transition: all 0.2s ease-in-out;
|
|
|
+ -o-transition: all 0.2s ease-in-out;
|
|
|
+ transition: all 0.2s ease-in-out;
|
|
|
+ .unread_num {
|
|
|
+ display: inline-block;
|
|
|
+ color: #fff;
|
|
|
+ background-color: #5182e4;
|
|
|
+ height: 14px;
|
|
|
+ padding: 0 2px;
|
|
|
+ line-height: 14px;
|
|
|
+ text-align: center;
|
|
|
+ border-radius: 2px;
|
|
|
+ font-size: 12px;
|
|
|
+ padding: 0 3px;
|
|
|
+ font-family: Arial;
|
|
|
+ -webkit-transform: scale(0.85);
|
|
|
+ -ms-transform: scale(0.85);
|
|
|
+ -o-transform: scale(0.85);
|
|
|
+ transform: scale(0.85);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .active {
|
|
|
+ box-shadow: 0 -2px 0 0 #5182e4 inset;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .noticeList_scroll {
|
|
|
+ height: 282px;
|
|
|
+ ::v-deep .el-scrollbar__wrap {
|
|
|
+ overflow-x: hidden;
|
|
|
+ }
|
|
|
+ .noticeList_item {
|
|
|
+ width: 100%;
|
|
|
+ height: auto;
|
|
|
+ position: relative;
|
|
|
+ cursor: pointer;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 12px 16px;
|
|
|
+ -webkit-transition: all 0.2s ease-in-out;
|
|
|
+ -o-transition: all 0.2s ease-in-out;
|
|
|
+ transition: all 0.2s ease-in-out;
|
|
|
+ zoom: 1;
|
|
|
+ .noticeItem_box {
|
|
|
+ float: left;
|
|
|
+ position: relative;
|
|
|
+ width: 100%;
|
|
|
+ .noticeItem_text {
|
|
|
+ color: rgba(10, 18, 32, 0.87);
|
|
|
+ font-weight: 700;
|
|
|
+ padding-left: 18px;
|
|
|
+ text-indent: -6px;
|
|
|
+ position: relative;
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 17px;
|
|
|
+ -webkit-transition: all 0.2s ease-in-out;
|
|
|
+ -o-transition: all 0.2s ease-in-out;
|
|
|
+ transition: all 0.2s ease-in-out;
|
|
|
+ .msg-icon {
|
|
|
+ position: absolute;
|
|
|
+ top: 2.5px;
|
|
|
+ left: 6px;
|
|
|
+ }
|
|
|
+ p {
|
|
|
+ word-break: break-all;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .noticeItem_time {
|
|
|
+ font-size: 12px;
|
|
|
+ height: 19px;
|
|
|
+ line-height: 19px;
|
|
|
+ color: rgba(10, 18, 32, 0.46);
|
|
|
+ margin-top: 4px;
|
|
|
+ padding-left: 18px;
|
|
|
+ .proname {
|
|
|
+ float: left;
|
|
|
+ display: block;
|
|
|
+ width: 80px;
|
|
|
+ overflow: hidden;
|
|
|
+ white-space: nowrap;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .noticeList_item:hover {
|
|
|
+ background-color: #f5f7f7;
|
|
|
+ }
|
|
|
+ .noticeList_item:after {
|
|
|
+ content: "";
|
|
|
+ display: block;
|
|
|
+ height: 0;
|
|
|
+ clear: both;
|
|
|
+ visibility: hidden;
|
|
|
+ }
|
|
|
+ .noticeList_item:before {
|
|
|
+ position: absolute;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ height: 1px;
|
|
|
+ padding: 0 16px;
|
|
|
+ background-color: #ebebeb;
|
|
|
+ content: "";
|
|
|
+ background-clip: content-box;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .notice_operate {
|
|
|
+ height: 40px;
|
|
|
+ line-height: 20px;
|
|
|
+ padding: 10px 16px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ background-color: rgba(242, 243, 245, 0.48);
|
|
|
+ box-shadow: inset 0 1px 0 0 rgba(10, 18, 32, 0.06);
|
|
|
+ zoom: 1;
|
|
|
+ .readAll {
|
|
|
+ float: left;
|
|
|
+ cursor: pointer;
|
|
|
+ -webkit-transition: all 0.2s ease-in-out;
|
|
|
+ -o-transition: all 0.2s ease-in-out;
|
|
|
+ transition: all 0.2s ease-in-out;
|
|
|
+ }
|
|
|
+ .readAll:hover {
|
|
|
+ text-decoration: underline;
|
|
|
+ }
|
|
|
+ .seeAll {
|
|
|
+ float: right;
|
|
|
+ color: #5182e4;
|
|
|
+ cursor: pointer;
|
|
|
+ font-weight: 700;
|
|
|
+ }
|
|
|
+ .seeAll:hover {
|
|
|
+ text-decoration: underline;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .el-icon-message-solid {
|
|
|
+ font-size: 22px;
|
|
|
+ }
|
|
|
+ ::v-deep .el-badge__content {
|
|
|
+ height: 16px;
|
|
|
+ line-height: 16px;
|
|
|
+ border: 1px solid transparent;
|
|
|
+ }
|
|
|
+}
|
|
|
+.notification-box:hover {
|
|
|
+ color: #d3d8e2;
|
|
|
+ background-color: #3f4f62;
|
|
|
+}
|
|
|
+.success-color {
|
|
|
+ color: #67c23a;
|
|
|
+}
|
|
|
+.error-color {
|
|
|
+ color: #f56c6c;
|
|
|
+}
|
|
|
+.warning-color {
|
|
|
+ color: #e6a23c;
|
|
|
+}
|
|
|
+.info-color {
|
|
|
+ color: #909399;
|
|
|
+}
|
|
|
+</style>
|