<template> <div v-loading="loading" ref="list-con" @blur="$emit('blur')" class="who-read-list pos-rel" > <template> <div class="d-flex tabs" :class="{ 'justify-content-center': !readlist.length || !unreadlist.length, }" > <div class="tab text-nowrap" :class="{ selected: tab === 1 }" @click="tab = 1" v-if="readlist.length" > <span>{{ readlist.length }}</span> <span>已读</span> </div> <div class="tab text-nowrap" :class="{ selected: tab === 2 }" @click="tab = 2" v-if="unreadlist.length" > <span>{{ unreadlist.length }}</span> <span>未读</span> </div> </div> <div class="items"> <el-scrollbar> <div class="member-item d-flex align-items-center" v-for="item in items" :key="`${item.eid}-${tab}`" > <avatar class="member-avatar" :src="item.avatar" :size="30" /> <span class="member-name text-truncate" :title="item.name" >{{ item.name }}</span > </div> </el-scrollbar> </div> </template> </div> </template> <script lang="ts"> import { Component, Prop, Ref, Vue } from "vue-property-decorator"; import { namespace } from "vuex-class"; import * as dto from "../model"; import { unique } from "../utils"; import avatar from "@/customer-service/components/avatar.vue"; import { ChatStore } from "@/customer-service/store/model"; import chat from "@/customer-service/xim/index"; import xim from "@/customer-service/xim/xim"; const chatStoreNamespace = namespace("chatStore"); @Component({ components: { avatar } }) export default class WhoReadList extends Vue { @chatStoreNamespace.State(ChatStore.STATE_CHAT_CURRENT_CHAT_ID) private readonly chatId!: ChatStore.STATE_CHAT_CURRENT_CHAT_ID; @chatStoreNamespace.State(ChatStore.STATE_CHAT_MY_ID) private readonly chatMyId!: ChatStore.STATE_CHAT_MY_ID; @Prop({ type: Number }) private msgId!: number; @Ref("list-con") private listCon!: HTMLElement; private readlist: { name: string; avatar: string }[] = []; private unreadlist: { name: string; avatar: string }[] = []; private loading = false; private tab = 1; private get items() { return this.tab === 1 ? this.readlist : this.unreadlist; } private startLoading() { this.loading = true; } private endLoading() { this.loading = false; } public async created() { this.startLoading(); await this.getReader(); this.endLoading(); } public mounted() { this.enableBlur(); } private enableBlur() { this.listCon.setAttribute("tabindex", "-1"); this.listCon.focus(); } private async getUserNameByid(eid: string) { const data = await chat.getSdk().model("user").detail(eid).query(); return data.row.first_name.value as string; } private async getReader() { if (this.chatId == null) return; if (this.msgId == null) return; const data = await xim.fetchMsgInBox(this.chatId, this.msgId); if (data == null) return; const readerlist = this.uniqueReaderList( data.args[0] as dto.OneWhoReadMessage[] ); this.readlist = await Promise.all( readerlist .filter((k) => k.is_read) .filter((k) => k.eid !== this.chatMyId) .map(async (k) => { const eid = k.eid; const name = await this.getUserNameByid(eid); return { eid, name, avatar: "", }; }) ); this.unreadlist = await Promise.all( readerlist .filter((k) => !k.is_read) .filter((k) => k.eid !== this.chatMyId) .map(async (k) => { const eid = k.eid; const name = await this.getUserNameByid(eid); return { eid, name, avatar: "", }; }) ); } private uniqueReaderList(data: dto.OneWhoReadMessage[]) { return unique(data, function (item, all) { return all.findIndex((k) => k.eid === item.eid); }); } } </script> <style lang="less" scoped> .who-read-list { background-color: #fff; box-shadow: 0px 0px 6px 0px rgba(0, 0, 0, 0.2); border-radius: 4px; border: 1px solid rgba(183, 191, 199, 1); min-height: 100px; position: absolute; color: #000; z-index: 2; margin-left: -100px; width: 125px; &.offset { margin-left: 0; } .number-count { font-size: 14px; color: #333333; margin-bottom: 15px; } } .tabs { border-bottom: 1px solid #f0f0f0; padding: 10px; .tab { cursor: pointer; span { font-size: 22px; & + span { font-size: 12px; } } &.selected { color: #4389f8; } & + .tab { margin-left: 30px; } } } .items { padding: 10px; padding-top: 0; padding-left: 20px; } .member-item { margin-top: 10px; .member-avatar, .member-name { display: inline-block; vertical-align: middle; } .member-avatar { margin-right: 10px; } } </style>