2024-04-09 19:34:19 +08:00

1094 lines
45 KiB
Vue

<template>
<div class="page-messenger">
<PageTitle :title="$L(tabActive==='dialog' ? '消息' : '通讯录')"/>
<div class="messenger-wrapper">
<div class="messenger-select">
<div class="messenger-search">
<div class="search-wrapper">
<div class="search-pre">
<Loading v-if="searchLoading"/>
<Icon v-else type="ios-search" />
</div>
<Input
v-if="tabActive==='dialog'"
v-model="dialogSearchKey"
ref="searchInput"
:placeholder="$L(loadDialogs > 0 ? '更新中...' : '搜索')"
@on-keydown="onKeydown"
clearable/>
<Input
v-else
v-model="contactsKey"
ref="contactInput"
:placeholder="$L('搜索')"
@on-keydown="onKeydown"
clearable/>
</div>
</div>
<div v-if="tabActive==='dialog' && !dialogSearchKey" class="messenger-nav">
<EDropdown
ref="navMenu"
trigger="click"
placement="bottom-start"
class="nav-menu"
@command="onActive">
<div class="nav-icon"><i class="taskfont">&#xe634;</i></div>
<EDropdownMenu slot="dropdown" class="messenger-nav-menu">
<EDropdownItem v-for="(item, key) in dialogMenus" :key="key" :command="item.type">
<div class="messenger-nav-item" :class="{active: dialogActive==item.type}">
<div class="nav-title">{{$L(item.name)}}</div>
<Badge class="nav-num" :overflow-count="999" :count="msgUnread(item.type)"/>
</div>
</EDropdownItem>
</EDropdownMenu>
</EDropdown>
<div
v-for="(item, key) in typeItems"
:key="key"
:class="{active:dialogActive==item.type}"
@click="onActive(item.type)">
<div class="nav-title">
<em>{{$L(item.name)}}</em>
<Badge class="nav-num" :overflow-count="999" :count="msgUnread(item.type)"/>
</div>
</div>
</div>
<div v-if="$isEEUiApp && !appNotificationPermission" class="messenger-notify-permission" @click="onOpenAppSetting">
{{$L('未开启通知权限')}}<i class="taskfont">&#xe733;</i>
</div>
<Scrollbar
ref="list"
class="messenger-list"
:hide-bar="this.operateVisible"
@touchstart.native="listTouch"
@on-scroll="listScroll">
<ul v-if="tabActive==='dialog'" ref="ul" class="dialog">
<template v-if="dialogList.length > 0">
<li
v-for="(dialog, key) in dialogList"
:ref="`dialog_${dialog.id}`"
:key="key"
:data-id="dialog.id"
:class="dialogClass(dialog)"
@click="openDialog({
dialog_id: dialog.id,
dialog_msg_id: dialog.search_msg_id,
search_msg_id: dialog.search_msg_id,
})"
v-longpress="handleLongpress"
:style="{'background-color':dialog.color}">
<template v-if="dialog.type=='group'">
<EAvatar v-if="dialog.avatar" class="img-avatar" :src="dialog.avatar" :size="42"></EAvatar>
<i v-else-if="dialog.group_type=='department'" class="taskfont icon-avatar department">&#xe75c;</i>
<i v-else-if="dialog.group_type=='project'" class="taskfont icon-avatar project">&#xe6f9;</i>
<i v-else-if="dialog.group_type=='task'" class="taskfont icon-avatar task">&#xe6f4;</i>
<i v-else-if="dialog.group_type=='okr'" class="taskfont icon-avatar task">&#xe6f4;</i>
<Icon v-else class="icon-avatar" type="ios-people" />
</template>
<div v-else-if="dialog.dialog_user" class="user-avatar"><UserAvatar :userid="dialog.dialog_user.userid" :size="42"/></div>
<Icon v-else class="icon-avatar" type="md-person" />
<div class="dialog-box">
<div class="dialog-title">
<div v-if="dialog.todo_num" class="todo">[{{$L('待办')}}{{formatTodoNum(dialog.todo_num)}}]</div>
<div v-if="$A.getDialogMention(dialog) > 0" class="mention">[@{{$A.getDialogMention(dialog)}}]</div>
<div v-if="dialog.bot" class="taskfont bot">&#xe68c;</div>
<template v-for="tag in $A.dialogTags(dialog)" v-if="tag.color != 'success'">
<Tag :color="tag.color" :fade="false" @on-click="openDialog(dialog.id)">{{$L(tag.text)}}</Tag>
</template>
<span>{{dialog.name}}</span>
<Icon v-if="dialog.type == 'user' && lastMsgReadDone(dialog.last_msg) && dialog.dialog_user.userid != userId" :type="lastMsgReadDone(dialog.last_msg)"/>
<em v-if="dialog.last_at">{{$A.formatTime(dialog.last_at)}}</em>
</div>
<div class="dialog-text no-dark-content">
<template v-if="dialog.extra_draft_has && dialog.id != dialogId">
<div class="last-draft">[{{$L('草稿')}}]</div>
<div class="last-text"><span>{{formatDraft(dialog.extra_draft_content)}}</span></div>
</template>
<template v-else>
<template v-if="dialog.type=='group' && dialog.last_msg && dialog.last_msg.userid">
<div v-if="dialog.last_msg.userid == userId" class="last-self">{{$L('')}}</div>
<UserAvatar v-else :userid="dialog.last_msg.userid" :show-name="true" :show-icon="false"/>
</template>
<div class="last-text">
<em v-if="formatMsgEmojiDesc(dialog.last_msg)">{{formatMsgEmojiDesc(dialog.last_msg)}}</em>
<span>{{$A.getMsgSimpleDesc(dialog.last_msg)}}</span>
</div>
</template>
<div v-if="dialog.silence" class="taskfont last-silence">&#xe7d7;</div>
</div>
</div>
<Badge class="dialog-num" :type="dialog.silence ? 'normal' : 'error'" :overflow-count="999" :count="$A.getDialogUnread(dialog, true)"/>
<div class="dialog-line"></div>
</li>
</template>
<li v-else-if="dialogSearchLoad === 0" class="nothing">
{{$L(dialogSearchKey ? `没有任何与"${dialogSearchKey}"相关的结果` : `没有任何会话`)}}
</li>
</ul>
<ul v-else class="contacts">
<template v-if="contactsFilter.length > 0">
<li v-for="items in contactsList">
<div class="label">{{items.az}}</div>
<ul>
<li v-for="(user, index) in items.list" :key="index" @click="openContacts(user)">
<div class="avatar"><UserAvatar :userid="user.userid" :size="30"/></div>
<div class="nickname">
<em>{{user.nickname}}</em>
<div v-if="user.tags" class="tags">
<span v-for="tag in user.tags" :style="tagField(tag,'style')">{{tagField(tag, 'label')}}</span>
</div>
</div>
<div v-if="user.loading" class="loading"><Loading/></div>
</li>
</ul>
</li>
<li class="loaded">
<template v-if="contactsKey">{{$L('搜索到' + contactsFilter.length + '位联系人')}}</template>
<template v-else>{{$L('' + contactsTotal + '位联系人')}}</template>
</li>
</template>
<li v-else-if="contactsLoad == 0" class="nothing">
{{$L(contactsKey ? `没有任何与"${contactsKey}"相关的结果` : `没有任何联系人`)}}
</li>
</ul>
<div class="operate-position" :style="operateStyles" v-show="operateVisible">
<Dropdown
trigger="custom"
transferClassName="scrollbar-hidden"
:placement="windowLandscape ? 'bottom' : 'top'"
:visible="operateVisible"
@on-clickoutside="operateVisible = false"
transfer>
<div :style="{userSelect:operateVisible ? 'none' : 'auto', height: operateStyles.height}"></div>
<DropdownMenu slot="list" class="messenger-dialog-operation">
<DropdownItem @click.native="handleTopClick">
<div class="item">
{{ $L(operateItem.top_at ? '取消置顶' : '置顶') }}
<i class="taskfont" v-html="operateItem.top_at ? '&#xe7e3;' : '&#xe7e6;'"></i>
</div>
</DropdownItem>
<DropdownItem @click.native="handleReadClick">
<div class="item">
{{ $L($A.getDialogUnread(operateItem, true) > 0 ? '标记已读' : '标记未读') }}
<i class="taskfont" v-html="$A.getDialogUnread(operateItem, true) > 0 ? '&#xe7e8;' : '&#xe7e9;'"></i>
</div>
</DropdownItem>
<DropdownItem @click.native="handleSilenceClick" :disabled="silenceDisabled(operateItem)">
<div class="item">
{{ $L(operateItem.silence ? '允许消息通知' : '消息免打扰') }}
<i class="taskfont" v-html="operateItem.silence ? '&#xe7eb;' : '&#xe7d7;'"></i>
</div>
</DropdownItem>
<DropdownItem @click.native="handleHideClick" :disabled="!!operateItem.top_at">
<div class="item">
{{ $L('不显示该会话') }}
<i class="taskfont">&#xe881;</i>
</div>
</DropdownItem>
<DropdownItem @click.native="handleColorClick(c.color)" v-for="(c, k) in taskColorList" :key="'c_' + k" :divided="k==0" v-if="k<6" >
<div class="item">
{{$L(c.name)}}
<i class="taskfont color" :style="{color:c.primary||'#ddd'}" v-html="c.color == (operateItem.color||'') ? '&#xe61d;' : '&#xe61c;'"></i>
</div>
</DropdownItem>
</DropdownMenu>
</Dropdown>
</div>
</Scrollbar>
<div class="messenger-menu">
<div class="menu-icon">
<Icon @click="onActive(null)" :class="{active:tabActive==='dialog'}" type="ios-chatbubbles" />
<Badge class="menu-num" :overflow-count="999" :count="msgUnread('all')"/>
</div>
<div class="menu-icon">
<Icon @click="tabActive='contacts'" :class="{active:tabActive==='contacts'}" type="md-person" />
</div>
</div>
</div>
<div v-if="activeNum > 0 && routeName === 'manage-messenger'" class="messenger-msg">
<div class="msg-dialog-bg">
<div class="msg-dialog-bg-icon"><Icon type="ios-chatbubbles" /></div>
<div class="msg-dialog-bg-text">{{$L('选择一个会话开始聊天')}}</div>
</div>
<DialogWrapper v-if="windowLandscape && dialogId > 0" :dialogId="dialogId" @on-active="scrollIntoActive" :auto-focus="$A.isDesktop()" location="messenger"/>
</div>
</div>
</div>
</template>
<script>
import {mapState} from "vuex";
import DialogWrapper from "./components/DialogWrapper";
import longpress from "../../directives/longpress";
import {Store} from "le5le-store";
const MessengerObject = {menuHistory: []};
export default {
components: {DialogWrapper},
directives: {longpress},
data() {
return {
firstLoad: true,
activeNum: 0,
tabActive: 'dialog',
dialogSearchLoad: 0,
dialogSearchKey: '',
dialogSearchList: [],
dialogActive: '',
dialogMenus: [
{type: '', name: '全部'},
{type: 'project', name: '项目'},
{type: 'task', name: '任务'},
{type: 'user', name: '单聊'},
{type: 'group', name: '群聊'},
{type: 'bot', name: '机器人'},
{type: 'mark', name: '标注'},
{type: '@', name: '@我'},
],
dialogHistory: MessengerObject.menuHistory,
contactsKey: '',
contactsLoad: 0,
contactsData: null,
contactsTotal: 0,
contactsCurrentPage: 1,
contactsHasMorePages: false,
contactsLastTime: 0,
operateItem: {},
operateStyles: {},
operateVisible: false,
clickAgainSubscribe: null,
}
},
async beforeRouteEnter(to, from, next) {
MessengerObject.menuHistory = await $A.IDBArray("dialogMenuHistory")
next()
},
mounted() {
const id = $A.runNum(this.$route.query.dialog_id);
if (id > 0) {
this.openDialog(id)
}
//
this.clickAgainSubscribe = Store.subscribe('clickAgainDialog', this.shakeUnread);
},
beforeDestroy() {
if (this.clickAgainSubscribe) {
this.clickAgainSubscribe.unsubscribe();
this.clickAgainSubscribe = null;
}
//
document.removeEventListener('keydown', this.shortcutEvent);
},
activated() {
this.updateDialogs(this.firstLoad ? 0 : 1000);
this.firstLoad = false;
//
this.$nextTick(_ => this.activeNum++)
//
if ($A.isEEUiApp) {
$A.eeuiAppSendMessage({action: 'getNotificationPermission'});
}
},
deactivated() {
this.updateDialogs(-1);
this.$nextTick(_ => this.activeNum--)
},
computed: {
...mapState(['cacheDialogs', 'loadDialogs', 'dialogId', 'dialogMsgId', 'dialogMsgs', 'messengerSearchKey', 'appNotificationPermission', 'taskColorList']),
routeName() {
return this.$route.name
},
typeItems() {
const {dialogActive, dialogMenus, dialogHistory} = this
const types = []
if (this.dialogHistory.includes(dialogActive)) {
types.push(...this.dialogHistory)
} else {
types.push('')
if (dialogActive) {
types.push(dialogActive)
}
dialogHistory.some(item => {
if (!types.includes(item)) {
types.push(item)
}
});
['project', 'task', 'user'].some(item => {
if (!types.includes(item)) {
types.push(item)
}
})
this.dialogHistory = types.slice(0, 4)
$A.IDBSave("dialogMenuHistory", this.dialogHistory)
}
//
return this.dialogHistory.map(type => {
return dialogMenus.find(item => item.type == type)
})
},
dialogList() {
const {dialogActive, dialogSearchKey, dialogSearchList} = this
if (dialogSearchList.length > 0) {
return dialogSearchList.sort((a, b) => {
// 搜索结果排在后面
return (a.is_search === true ? 1 : 0) - (b.is_search === true ? 1 : 0)
})
}
if (dialogActive == '' && dialogSearchKey == '') {
return this.cacheDialogs.filter(dialog => this.filterDialog(dialog)).sort(this.dialogSort);
}
if (dialogActive == 'mark' && !dialogSearchKey) {
const lists = [];
this.dialogMsgs.filter(h => h.tag).forEach(h => {
let dialog = $A.cloneJSON(this.cacheDialogs).find(p => p.id == h.dialog_id)
if (dialog) {
dialog.last_msg = h;
dialog.search_msg_id = h.id;
lists.push(dialog);
}
});
return lists;
}
const list = this.cacheDialogs.filter(dialog => {
if (!this.filterDialog(dialog)) {
return false;
}
if (dialogSearchKey) {
const {name, pinyin, last_msg} = dialog;
let searchString = `${name} ${pinyin}`
if (last_msg) {
switch (last_msg.type) {
case 'text':
searchString += ` ${last_msg.msg.text.replace(/<[^>]+>/g, "")}`
break
case 'meeting':
case 'file':
searchString += ` ${last_msg.msg.name}`
break
}
}
if (!$A.strExists(searchString, dialogSearchKey)) {
return false;
}
} else if (dialogActive) {
switch (dialogActive) {
case 'project':
case 'task':
if (dialogActive != dialog.group_type) {
return false;
}
break;
case 'user':
if (dialogActive != dialog.type || dialog.bot) {
return false;
}
break;
case 'group':
if (dialogActive != dialog.type || ['project', 'task'].includes(dialog.group_type)) {
return false;
}
break;
case 'bot':
if (!dialog.bot) {
return false;
}
break;
case '@':
if (!$A.getDialogMention(dialog)) {
return false;
}
break;
default:
return false;
}
}
return true;
})
return list.sort(this.dialogSort)
},
contactsFilter() {
const {contactsData, contactsKey} = this;
if (contactsData === null) {
return [];
}
if (contactsKey) {
return contactsData.filter(item => $A.strExists(`${item.email} ${item.nickname} ${item.profession} ${item.pinyin}`, contactsKey))
}
return contactsData;
},
contactsList() {
const list = [];
this.contactsFilter.some(user => {
let az = user.az ? user.az.toUpperCase() : "#";
let item = list.find(item => item.az == az);
if (item) {
if (item.list.findIndex(({userid}) => userid == user.userid) === -1) {
item.list.push(user)
}
} else {
list.push({
az,
list: [user]
})
}
})
return list;
},
msgUnread() {
return function (type) {
let num = 0
this.cacheDialogs.some((dialog) => {
switch (type) {
case 'project':
case 'task':
if (type != dialog.group_type) {
return false
}
break;
case 'user':
if (type != dialog.type || dialog.bot) {
return false
}
break;
case 'group':
if (type != dialog.type || ['project', 'task'].includes(dialog.group_type)) {
return false
}
break;
case 'bot':
if (!dialog.bot) {
return false;
}
break;
case 'mark':
return false;
case '@':
return false;
}
num += $A.getDialogNum(dialog);
});
return num;
}
},
searchLoading({tabActive, loadDialogs, dialogSearchLoad, contactsLoad}) {
if (tabActive==='dialog') {
return loadDialogs > 0 || dialogSearchLoad > 0
} else {
return contactsLoad > 0
}
},
},
watch: {
'$route': {
handler({params}) {
if (['dialog', 'contacts'].includes(params.dialogAction)) {
this.tabActive = params.dialogAction
}
if (params.dialog_id) {
this.tabActive = 'dialog'
const id = $A.runNum(params.dialog_id);
if (id > 0) {
this.openDialog(id)
}
this.clickAgainSubscribe = Store.subscribe('clickAgainDialog', this.shakeUnread);
}
},
immediate: true
},
messengerSearchKey: {
handler(obj) {
this.$nextTick(_ => {
this.dialogSearchKey = obj.dialog
this.contactsKey = obj.contacts
})
},
deep: true
},
dialogSearchKey(val) {
this.$store.state.messengerSearchKey.dialog = val
if ($A.loadVConsole(val)) {
this.dialogSearchKey = '';
return;
}
if (this.tabActive === 'dialog') {
// todo 日志输出对话详情信息
if (/^info\.\d+$/.test(val)) {
console.log(this.cacheDialogs.find(item => item.id == val.replace('info.', '')));
}
}
//
this.dialogSearchList = [];
if (val == '') {
return
}
this.__search_timer && clearTimeout(this.__search_timer)
this.__search_timer = setTimeout(this.searchDialog, 600)
this.dialogSearchLoad++
setTimeout(_ => this.dialogSearchLoad--, 600)
},
contactsKey(val) {
this.$store.state.messengerSearchKey.contacts = val
if (val == '') {
return;
}
this.contactsLoad++;
setTimeout(() => {
if (this.contactsKey == val) {
this.getContactsList(1);
}
this.contactsLoad--;
}, 600);
},
windowActive(val) {
this.updateDialogs(val ? 1000 : -1);
},
tabActive: {
handler(val) {
if (val == 'contacts') {
if ($A.Time() - this.contactsLastTime > 24 * 3600) {
this.contactsData = null; // 24个小时重新加载列表
}
if (this.contactsData === null) {
this.getContactsList(1);
} else {
this.updateContactsList(1000);
}
} else {
this.updateDialogs(1000);
}
},
immediate: true
},
dialogId: {
handler(id) {
if (id > 0) {
this.scrollIntoActive()
}
},
immediate: true
},
dialogActive(){
this.dialogSearchList = [];
if(this.dialogActive == 'mark' && !this.dialogSearchKey){
this.searchTagDialog()
}
}
},
methods: {
listTouch() {
if (this.$refs.navMenu?.visible) {
this.$refs.navMenu.hide()
}
},
listScroll() {
if (this.scrollE() < 10) {
this.getContactsNextPage()
}
this.operateVisible = false;
},
scrollE() {
if (!this.$refs.list) {
return 0
}
const scrollInfo = this.$refs.list.scrollInfo()
return scrollInfo.scrollE
},
onKeydown(e) {
if (e.key === "Escape") {
this.$refs.searchInput?.handleClear()
this.$refs.contactInput?.handleClear()
}
},
onActive(type) {
if (type === null) {
if (this.tabActive !== 'dialog') {
this.tabActive = 'dialog'
return;
}
type = this.dialogActive
}
if (this.dialogActive == type) {
this.shakeUnread() // 再次点击滚动到未读条目
} else {
this.dialogActive = type
}
},
shakeUnread() {
let index = this.dialogList.findIndex(dialog => $A.getDialogNum(dialog) > 0)
if (index === -1) {
index = this.dialogList.findIndex(dialog => dialog.todo_num > 0)
}
if (index === -1) {
index = this.dialogList.findIndex(dialog => $A.getDialogUnread(dialog, true) > 0)
}
if (index > -1) {
const el = this.$refs[`dialog_${this.dialogList[index]?.id}`]
if (el && el[0]) {
if (el[0].classList.contains("common-shake")) {
return
}
$A.scrollIntoViewIfNeeded(el[0])
requestAnimationFrame(_ => {
el[0].classList.add("common-shake")
setTimeout(_ => {
el[0].classList.remove("common-shake")
}, 600)
})
}
}
},
dialogClass(dialog) {
if (this.dialogSearchKey) {
return null
}
return {
top: dialog.top_at,
active: dialog.id == this.dialogId && (dialog.search_msg_id == this.dialogMsgId || !this.dialogMsgId),
operate: this.operateVisible && dialog.id == this.operateItem.id,
completed: $A.dialogCompleted(dialog)
}
},
dialogSort(a, b) {
// 根据置顶时间排序
if (a.top_at || b.top_at) {
return $A.Date(b.top_at) - $A.Date(a.top_at);
}
// 根据未读数排序
if (a.todo_num > 0 || b.todo_num > 0) {
return b.todo_num - a.todo_num;
}
// 根据草稿排序
if (a.extra_draft_has || b.extra_draft_has) {
return b.extra_draft_has - a.extra_draft_has;
}
// 根据最后会话时间排序
return $A.Date(b.last_at) - $A.Date(a.last_at);
},
openDialog(dialogId) {
if (this.operateVisible) {
return
}
//
if ($A.isJson(dialogId) && $A.leftExists(dialogId.dialog_id, "u:")) {
this.$store.dispatch("openDialogUserid", $A.leftDelete(dialogId.dialog_id, "u:")).catch(({msg}) => {
$A.modalError(msg)
})
} else {
this.$store.dispatch("openDialog", dialogId)
}
},
openContacts(user) {
if (user.loading) {
return
}
this.$set(user, 'loading', true);
this.$store.dispatch("openDialogUserid", user.userid).then(_ => {
if (this.windowLandscape) {
this.tabActive = 'dialog';
}
}).catch(({msg}) => {
$A.modalError(msg)
}).finally(_ => {
this.$set(user, 'loading', false);
});
},
tagField(item, field) {
if (!$A.isJson(item)) {
item = {label: item}
}
switch (field) {
case 'style':
return item.style || null
case 'label':
return item.label
}
return null
},
filterDialog(dialog) {
if ((dialog.id > 0 && dialog.id == this.dialogId) || dialog.top_at || dialog.todo_num > 0 || $A.getDialogNum(dialog) > 0) {
return true
}
if (dialog.name === undefined || dialog.dialog_delete === 1) {
return false;
}
if (dialog.hide || !dialog.last_at) {
return false;
}
if (dialog.type == 'group') {
if (['project', 'task'].includes(dialog.group_type) && $A.isJson(dialog.group_info)) {
if (dialog.group_type == 'task' && dialog.group_info.complete_at) {
// 已完成5天后隐藏对话
let time = Math.max($A.Date(dialog.last_at, true), $A.Date(dialog.group_info.complete_at, true))
if (5 * 86400 + time < $A.Time()) {
return false
}
}
if (dialog.group_info.deleted_at) {
// 已删除2天后隐藏对话
let time = Math.max($A.Date(dialog.last_at, true), $A.Date(dialog.group_info.deleted_at, true))
if (2 * 86400 + time < $A.Time()) {
return false
}
}
if (dialog.group_info.archived_at) {
// 已归档3天后隐藏对话
let time = Math.max($A.Date(dialog.last_at, true), $A.Date(dialog.group_info.archived_at, true))
if (3 * 86400 + time < $A.Time()) {
return false
}
}
}
}
return true;
},
searchDialog() {
const key = this.dialogSearchKey
if (key == '') {
return
}
//
this.dialogSearchLoad++;
this.$store.dispatch("call", {
url: 'dialog/search',
data: {key},
}).then(({data}) => {
if (key !== this.dialogSearchKey) {
return
}
const list = $A.cloneJSON(this.dialogList)
const msgIds = [];
const userIds = [];
list.forEach(item => {
if (item.last_msg && !msgIds.includes(item.last_msg.id)) {
msgIds.push(item.last_msg.id)
}
if (item.dialog_user && !userIds.includes(item.dialog_user.userid)) {
userIds.push(item.dialog_user.userid)
}
})
data.some(item => {
if ($A.leftExists(item.id, "u:")) {
if (!userIds.includes(item.dialog_user.userid)) {
list.push(Object.assign(item, {is_search: true}))
}
} else {
if (!item.last_msg || !msgIds.includes(item.last_msg.id)) {
list.push(Object.assign(item, {is_search: true}))
}
}
})
this.dialogSearchList = list;
}).finally(_ => {
this.dialogSearchLoad--;
});
},
searchTagDialog() {
this.dialogSearchLoad++;
this.$store.dispatch("call", {
url: 'dialog/search/tag',
}).then(({data}) => {
const msgIds = [];
const lists = [];
this.dialogList.forEach(h=>{
lists.push(h);
msgIds.push(h.search_msg_id)
});
data.some(item => {
if (!item.last_msg || !msgIds.includes(item.search_msg_id)) {
lists.push(Object.assign(item, {is_search: true}))
}
})
this.dialogSearchList = lists;
}).finally(_ => {
this.dialogSearchLoad--;
});
},
getContactsList(page) {
this.contactsLoad++;
const key = this.contactsKey
this.$store.dispatch("call", {
url: 'users/search',
data: {
keys: {key},
sorts: {
az: 'asc'
},
page: page,
pagesize: 50
},
}).then(({data}) => {
if (key == '') {
this.contactsTotal = data.total;
}
if (this.contactsData === null) {
this.contactsData = [];
}
data.data.some((user) => {
if (this.contactsData.findIndex(item => item.userid == user.userid) === -1) {
this.contactsData.push(user)
}
});
this.contactsCurrentPage = data.current_page;
this.contactsHasMorePages = data.current_page < data.last_page;
this.$nextTick(this.getContactsNextPage);
}).catch(() => {
if (key == '') {
this.contactsTotal = 0;
}
this.contactsHasMorePages = false;
}).finally(_ => {
this.contactsLoad--;
this.contactsLastTime = $A.Time()
});
},
getContactsNextPage() {
if (this.scrollE() < 10
&& this.tabActive === 'contacts'
&& this.contactsLoad === 0
&& this.contactsHasMorePages) {
this.getContactsList(this.contactsCurrentPage + 1);
}
},
updateContactsList(timeout) {
this.__updateContactsList && clearTimeout(this.__updateContactsList)
if (timeout > -1) {
this.__updateContactsList = setTimeout(_ => {
if (this.tabActive === 'contacts') {
this.$store.dispatch("call", {
url: 'users/search',
data: {
updated_time: this.contactsLastTime,
take: 100
},
}).then(({data}) => {
data.some((user) => {
const index = this.contactsData.findIndex(item => item.userid == user.userid);
if (index > -1) {
this.contactsData.splice(index, 1, user);
} else {
this.contactsData.push(user);
}
});
}).finally(_ => {
this.contactsLastTime = $A.Time()
});
}
}, timeout)
}
},
formatDraft(value) {
return value?.replace(/<img[^>]*>/gi, `[${$A.L('图片')}]`)
.replace(/<[^>]*>/g, '')
.replace(/&nbsp;/g, ' ')|| null
},
formatTodoNum(num) {
return num > 999 ? '999+' : (num > 1 ? num : '')
},
formatMsgEmojiDesc(data) {
if ($A.isJson(data) && $A.arrayLength(data.emoji) > 0) {
return data.emoji[0].symbol;
}
return null;
},
lastMsgReadDone(data) {
if ($A.isJson(data)) {
const {userid, percentage} = data;
if (userid === this.userId) {
return percentage === 100 ? 'md-done-all' : 'md-checkmark';
}
}
return null;
},
scrollIntoActive() {
this.$nextTick(() => {
if (this.windowLandscape && this.$refs.list) {
const active = this.$refs.list.querySelector(".active")
if (active) {
$A.scrollIntoViewIfNeeded(active);
} else {
const dialog = this.cacheDialogs.find(({id}) => id == this.dialogId)
if (dialog && this.dialogActive) {
this.dialogActive = '';
this.$nextTick(() => {
const active = this.$refs.list.querySelector(".active")
if (active) {
$A.scrollIntoViewIfNeeded(active);
}
});
}
}
}
})
},
handleLongpress(event, el) {
if (this.dialogSearchKey) {
return;
}
const dialogId = $A.getAttr(el, 'data-id')
const dialogItem = this.dialogList.find(item => item.id == dialogId)
if (!dialogItem) {
return
}
this.operateVisible = false;
this.operateItem = $A.isJson(dialogItem) ? dialogItem : {};
this.$nextTick(() => {
const rect = el.getBoundingClientRect();
this.operateStyles = {
left: `${event.clientX}px`,
top: `${rect.top + this.windowScrollY}px`,
height: rect.height + 'px',
}
this.operateVisible = true;
})
},
handleTopClick() {
this.$store.dispatch("call", {
url: 'dialog/top',
data: {
dialog_id: this.operateItem.id,
},
}).then(({data}) => {
this.$store.dispatch("saveDialog", data);
this.$nextTick(this.scrollIntoActive);
}).catch(({msg}) => {
$A.modalError(msg);
});
},
handleReadClick() {
this.$store.dispatch("showSpinner", 600)
this.$store.dispatch("dialogMsgMark", {
type: $A.getDialogUnread(this.operateItem, true) > 0 ? 'read' : 'unread',
dialog_id: this.operateItem.id,
}).catch(({msg}) => {
$A.modalError(msg)
}).finally(_ => {
this.$store.dispatch("hiddenSpinner")
})
},
handleSilenceClick() {
if (this.silenceDisabled(this.operateItem)) {
return
}
this.$store.dispatch("call", {
url: 'dialog/msg/silence',
data: {
dialog_id: this.operateItem.id,
type: this.operateItem.silence ? 'cancel' : 'set'
},
}).then(({data}) => {
this.$store.dispatch("saveDialog", data);
}).catch(({msg}) => {
$A.modalError(msg);
});
},
handleHideClick() {
this.$store.dispatch("call", {
url: 'dialog/hide',
data: {
dialog_id: this.operateItem.id,
},
}).then(({data}) => {
if (this.dialogId == this.operateItem.id) {
this.$store.dispatch("openDialog", 0)
}
this.$store.dispatch("saveDialog", data);
}).catch(({msg}) => {
$A.modalError(msg);
});
},
handleColorClick(color) {
this.$store.dispatch("call", {
url: 'dialog/msg/color',
data: {
dialog_id: this.operateItem.id,
color: color
},
}).then(({data}) => {
this.$store.dispatch("saveDialog", data);
}).catch(({msg}) => {
$A.modalError(msg);
});
},
updateDialogs(timeout) {
this.__updateDialogs && clearTimeout(this.__updateDialogs)
if (timeout > -1) {
this.__updateDialogs = setTimeout(_ => {
if (this.tabActive === 'dialog' && this.routeName === 'manage-messenger') {
this.$store.dispatch("getDialogAuto").catch(() => {});
}
}, timeout)
}
},
onOpenAppSetting() {
$A.eeuiAppSendMessage({
action: 'gotoSetting',
});
},
silenceDisabled(data) {
const {type, group_type} = data
return type === 'group' && group_type !== 'user'
},
}
}
</script>