背景
实现如上图效果:点击小铃铛,从右侧展示通知,点击其中一条跳,转到一个新页面;小铃铛数目减少;
实现
index.vue
<template>
<el-drawer
v-if="visible"
:visible.sync="visible"
:destroy-on-close="true"
:size="width"
direction="rtl"
custom-class="drawer__custom"
@close="onClosed">
<!-- 公告通知 -->
<template slot="title">
<div class="header">
<d2-icon-svg name="icon_status" />
<span>{{ language == 'cn'? name : nameEn }}</span>
</div>
</template>
<!-- 工单内容 -->
<div class="content">
<notice-content
v-if="noticeList && Object.keys(noticeList)"
:notices="noticeList"
@viewDetail="onViewDetail"
@loadMore="loadMore" />
</div>
</el-drawer>
</template>
<script>
import { mapState } from 'vuex';
import NoticeContent from './NoticeContent.vue';
import { readNoticeService } from '@/api/notice';
import { updateMessageStatus, getUnreadMessageList } from '@/api/workOrder';
export default {
name: 'NoticeDrawer',
components: { NoticeContent },
data() {
return {
name: '通知',
nameEn: 'Notification',
visible: false,
width: 480,
pageNum: 1,
pageSize: 5,
currentViewNotice: {},
noticeList: [],
loadingInstance: null,
};
},
computed: {
...mapState('d2admin/profile', ['language']),
...mapState('d2admin/user', ['info']),
},
methods: {
open(list) {
this.visible = true;
this.noticeList = Object.assign([], list);
},
loadMore() {
// 分页累加
this.pageNum += 1;
this.showLoading();
getUnreadMessageList({ pageNum: this.pageNum, pageSize: this.pageSize })
.then(response => {
const { data } = response.data;
const { rows } = data;
this.noticeList = [...this.noticeList, ...rows];
}).finally(() => {
this.loadingInstance.close();
});
},
onViewDetail(notice, idx) {
// 未读状态下才更新文章状态
// if (!notice.readFlag) {
// this.readNotice(notice.noticeNo);
// }
this.visible = false;
const params = {
formNo: notice.formNo,
direction: 'T'
};
updateMessageStatus(params)
.then((response) => {
const result = (response.data || {}).data || {};
this.$emit('updateReadCount');
const routePath = `/work-order/dialogue?formNo=${notice.formNo}`;
window.open(this.$router.resolve(routePath).href, '_blank');
});
console.log(notice, 'notice, idxnotice, idx');
},
readNotice(noticeNo) {
readNoticeService({ noticeNo, operator: this.info.name })
.then(response => {
// 文档已读,更新数据,把当前数据的readFlag置为已读
this.noticeList = this.noticeList.map(item => {
if (item.noticeNo === noticeNo) {
item.readFlag = true;
}
return item;
});
});
},
showLoading() {
this.loadingInstance = this.$loading({
lock: true,
text: 'Loading',
spinner: 'el-icon-loading',
background: 'rgba(256,256,256,.7)',
target: document.querySelector('.content')
});
},
onClosed() {
this.visible = false;
this.$emit('updateReadCount');
Object.assign(this.$data, this.$options.data());
},
},
};
</script>
<style scoped lang="scss">
/deep/ .el-drawer {
padding-right: 0 !important;
.el-drawer__header {
padding-right: 30px;
}
}
.drawer__custom {
.header {
span {
margin-left: 8px;
}
}
.content {
display: flex;
//height: calc(100vh - 80px);
}
}
</style>
NoticeContent.vue
<template>
<div ref="notice" class="notice_wrapper" @scroll="onScrollNotice($event)">
<div
v-for="(notice, index) of notices"
:key="index"
:class="['notice_item', active === index ? 'active' : '']"
@click="onViewDetails(notice, index)">
<header class="header">
<span class="date">{{
$util.string.betterDisplay(
$util.datetime.formatUtcToZoneTime(notice.createTime)
)
}}</span>
<el-tag v-if="!notice.readFlag" color="#FFB8BB">NEW</el-tag>
</header>
<div class="content">
<div class="title">{{ language == 'cn'? name : nameEn }}:{{ notice.formNo }}</div>
<div v-if="notice.type == 'system_contact'" ref="content" class="message">
{{ language == 'cn' ? parerFont(notice.content).cn : parerFont(notice.content).en }}
</div>
<div v-else ref="content" class="message">
{{ notice.content }}
</div>
</div>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex';
export default {
name: 'NoticeContent',
props: {
notices: {
type: Array,
default: () => [],
required: true,
},
},
data() {
return {
active: '',
name: '工单单号',
nameEn: 'Ticket Number'
};
},
computed: {
...mapState('d2admin/profile', ['language']),
},
methods: {
onScrollNotice(evt) {
const { scrollTop, offsetHeight, scrollHeight } = evt.target;
// 滑到底部
if ((scrollTop + offsetHeight) === scrollHeight) {
this.$emit('loadMore');
}
},
onViewDetails(notice, idx) {
this.active = idx;
this.$emit('viewDetail', notice);
},
parerFont(text) {
return JSON.parse(text);
}
},
};
</script>
<style scoped lang="scss">
.notice_wrapper {
width: 420px;
height: calc(100vh - 80px);
overflow-y: auto;
padding-right:4px;
margin-right: 26px;
box-sizing: border-box;
.notice_item {
padding: 24px;
min-height: 120px;
border: 1px solid $color-neutral-light-100;
border-radius: $common-radius_12;
background-color: #ffffff;
cursor: pointer;
margin-bottom: 16px;
&:hover {
background-color: $color-neutral-light-50;
}
&.active {
background-color: $color-active-100;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
.date {
color: $color-neutral-light-400;
font-size: 12px;
font-weight: 400;
line-height: 18px;
}
/deep/ .el-tag {
color: #1a1c21;
border-style: none;
border-radius: 14px;
font-size: 12px;
line-height: 18px;
padding: 2px 8px;
height: 100%;
}
}
.content {
.title {
margin: 14px 0 8px;
color: $color-neutral-light-500;
font-size: 16px;
font-weight: 600;
line-height: 24px;
}
.message {
color: #727880;
font-weight: 400;
line-height: 21px;
overflow: hidden;
/* 溢出用省略号显示 */
text-overflow: ellipsis;
/* 作为弹性伸缩盒子模型显示 */
display: -webkit-box;
/* 设置伸缩盒子的子元素排列方式:从上到下垂直排列 */
-webkit-box-orient:vertical;
/* 显示的行数 */
-webkit-line-clamp: 2;
}
}
}
}
</style>
引入使用
<notice-drawer ref="noticeDrawers" @updateReadCount="queryNoticeCountTotal" />
import { getUnreadMessageList } from '@/api/workOrder';
export default {
name: 'WorkOrder',
components: {
NoticeDrawer,
},
data() {
return {
noticeTotal: 0,
noticeList: [],
};
},
created() {
this.queryNoticeCountTotal();
},
methods: {
queryNoticeCountTotal() {
getUnreadMessageList({ pageSize: 5, pageNum: 1 })
.then(response => {
if (response.data) {
const { data } = response.data;
const { rows, total } = data;
this.noticeList = rows;
this.noticeTotal = total;
}
});
},
}
}
接口
const hostType = 'BASIC_GATE';
export const getUnreadMessageList = (data = {}) => {
const extraData = {
hostType
};
return post('/myNotice/getUnreadMessageList', data, extraData);
};