|
|
|
@ -1,35 +1,62 @@ |
|
|
|
<template> |
|
|
|
<template> |
|
|
|
<div> |
|
|
|
<div> |
|
|
|
<el-dialog :title="title" :visible.sync="visible" width="38%" append-to-body :before-close="handleClose"> |
|
|
|
<el-dialog |
|
|
|
|
|
|
|
:title="title" |
|
|
|
|
|
|
|
:visible.sync="visible" |
|
|
|
|
|
|
|
width="38%" |
|
|
|
|
|
|
|
append-to-body |
|
|
|
|
|
|
|
:before-close="handleClose" |
|
|
|
|
|
|
|
> |
|
|
|
<el-row :gutter="20" class="body"> |
|
|
|
<el-row :gutter="20" class="body"> |
|
|
|
<!-- 左侧:联系人选择区域 --> |
|
|
|
<!-- 左侧:联系人选择区域 --> |
|
|
|
<el-col :span="12"> |
|
|
|
<el-col :span="12"> |
|
|
|
<!-- 搜索框 --> |
|
|
|
<!-- 搜索框 --> |
|
|
|
<el-input v-model="searchText" placeholder="搜索联系人" suffix-icon="el-icon-search" clearable |
|
|
|
<el-input |
|
|
|
@keyup.enter.native="handleSearch" @clear="handleClearSearch" style="margin-bottom: 10px" /> |
|
|
|
v-model="searchText" |
|
|
|
|
|
|
|
placeholder="搜索联系人" |
|
|
|
|
|
|
|
suffix-icon="el-icon-search" |
|
|
|
|
|
|
|
clearable |
|
|
|
|
|
|
|
@keyup.enter.native="handleSearch" |
|
|
|
|
|
|
|
@clear="handleClearSearch" |
|
|
|
|
|
|
|
style="margin-bottom: 10px" |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 标签页 --> |
|
|
|
<!-- 标签页 --> |
|
|
|
<el-tabs v-model="activeName" @tab-click="handleClick"> |
|
|
|
<el-tabs v-model="activeName" @tab-click="handleClick"> |
|
|
|
<!-- 最近联系人 --> |
|
|
|
<!-- 最近联系人 --> |
|
|
|
<el-tab-pane label="最近联系人" name="recentContacts"> |
|
|
|
<el-tab-pane label="最近联系人" name="recentContacts"> |
|
|
|
<div v-loading="loading" class="contact-list"> |
|
|
|
<div v-loading="loading" class="contact-list"> |
|
|
|
<div v-for="member in displayMembers" :key="member.id" :class="[ |
|
|
|
<div |
|
|
|
'member-item', |
|
|
|
v-for="member in displayMembers" |
|
|
|
{ |
|
|
|
:key="member.id" |
|
|
|
active: isSelected(member.id), |
|
|
|
:class="[ |
|
|
|
offline: !member.online, |
|
|
|
'member-item', |
|
|
|
}, |
|
|
|
{ |
|
|
|
]" @click="toggleSelect(member)"> |
|
|
|
active: isSelected(member.id), |
|
|
|
<el-checkbox v-model="member.selected" :disabled="isSelectDisabled && !member.selected" |
|
|
|
offline: !member.online, |
|
|
|
@change="toggleSelect(member)"> |
|
|
|
}, |
|
|
|
|
|
|
|
]" |
|
|
|
|
|
|
|
@click="toggleSelect(member)" |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
<el-checkbox |
|
|
|
|
|
|
|
v-model="member.selected" |
|
|
|
|
|
|
|
:disabled="isSelectDisabled && !member.selected" |
|
|
|
|
|
|
|
@change="toggleSelect(member)" |
|
|
|
|
|
|
|
> |
|
|
|
<div class="member-item-label"> |
|
|
|
<div class="member-item-label"> |
|
|
|
<el-avatar :src="member.avatar" icon="el-icon-user-solid" /> |
|
|
|
<el-avatar |
|
|
|
|
|
|
|
:src="member.avatar" |
|
|
|
|
|
|
|
icon="el-icon-user-solid" |
|
|
|
|
|
|
|
/> |
|
|
|
<span class="member-name">{{ member.name }}</span> |
|
|
|
<span class="member-name">{{ member.name }}</span> |
|
|
|
<span v-if="member.online" class="online-dot" /> |
|
|
|
<span v-if="member.online" class="online-dot" /> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</el-checkbox> |
|
|
|
</el-checkbox> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<el-empty v-if="!loading && displayMembers.length === 0" description="暂无联系人" /> |
|
|
|
<el-empty |
|
|
|
|
|
|
|
v-if="!loading && displayMembers.length === 0" |
|
|
|
|
|
|
|
description="暂无联系人" |
|
|
|
|
|
|
|
/> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</el-tab-pane> |
|
|
|
</el-tab-pane> |
|
|
|
|
|
|
|
|
|
|
|
@ -38,7 +65,11 @@ |
|
|
|
<div v-loading="loading" class="contact-list"> |
|
|
|
<div v-loading="loading" class="contact-list"> |
|
|
|
<div v-for="group in recentGroups" :key="group.id"> |
|
|
|
<div v-for="group in recentGroups" :key="group.id"> |
|
|
|
<!-- 群组标题 --> |
|
|
|
<!-- 群组标题 --> |
|
|
|
<div class="group-header" :class="{ expanded: group.expanded }" @click="toggleGroupExpand(group)"> |
|
|
|
<div |
|
|
|
|
|
|
|
class="group-header" |
|
|
|
|
|
|
|
:class="{ expanded: group.expanded }" |
|
|
|
|
|
|
|
@click="toggleGroupExpand(group)" |
|
|
|
|
|
|
|
> |
|
|
|
<el-avatar :size="32" :src="group.avatar" /> |
|
|
|
<el-avatar :size="32" :src="group.avatar" /> |
|
|
|
<span class="group-name">{{ group.name }}</span> |
|
|
|
<span class="group-name">{{ group.name }}</span> |
|
|
|
<i class="el-icon-arrow-right expand-icon" /> |
|
|
|
<i class="el-icon-arrow-right expand-icon" /> |
|
|
|
@ -46,21 +77,35 @@ |
|
|
|
<!-- 群成员列表 --> |
|
|
|
<!-- 群成员列表 --> |
|
|
|
<div v-if="group.expanded"> |
|
|
|
<div v-if="group.expanded"> |
|
|
|
<!-- 全选 --> |
|
|
|
<!-- 全选 --> |
|
|
|
<div class="member-item" :class="{ selected: group.allSelected }" |
|
|
|
<div |
|
|
|
@click="toggleGroupAllSelect(group)"> |
|
|
|
class="member-item" |
|
|
|
<el-checkbox v-model="group.allSelected" @change="toggleGroupAllSelect(group)" /> |
|
|
|
:class="{ selected: group.allSelected }" |
|
|
|
|
|
|
|
@click="toggleGroupAllSelect(group)" |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
<el-checkbox |
|
|
|
|
|
|
|
v-model="group.allSelected" |
|
|
|
|
|
|
|
@change="toggleGroupAllSelect(group)" |
|
|
|
|
|
|
|
/> |
|
|
|
<span class="member-name">全选</span> |
|
|
|
<span class="member-name">全选</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<!-- 成员列表 --> |
|
|
|
<!-- 成员列表 --> |
|
|
|
<div v-for="member in group.members" :key="member.id" :class="[ |
|
|
|
<div |
|
|
|
'member-item', |
|
|
|
v-for="member in group.members" |
|
|
|
{ |
|
|
|
:key="member.id" |
|
|
|
active: isSelected(member.id), |
|
|
|
:class="[ |
|
|
|
offline: !member.online, |
|
|
|
'member-item', |
|
|
|
}, |
|
|
|
{ |
|
|
|
]" @click="toggleSelect(member)"> |
|
|
|
active: isSelected(member.id), |
|
|
|
<el-checkbox v-model="member.selected" :disabled="isSelectDisabled && !member.selected" |
|
|
|
offline: !member.online, |
|
|
|
@change="toggleSelect(member)"> |
|
|
|
}, |
|
|
|
|
|
|
|
]" |
|
|
|
|
|
|
|
@click="toggleSelect(member)" |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
<el-checkbox |
|
|
|
|
|
|
|
v-model="member.selected" |
|
|
|
|
|
|
|
:disabled="isSelectDisabled && !member.selected" |
|
|
|
|
|
|
|
@change="toggleSelect(member)" |
|
|
|
|
|
|
|
> |
|
|
|
<div class="member-item-label"> |
|
|
|
<div class="member-item-label"> |
|
|
|
<el-avatar :size="32" :src="member.avatar" /> |
|
|
|
<el-avatar :size="32" :src="member.avatar" /> |
|
|
|
<span class="member-name">{{ member.name }}</span> |
|
|
|
<span class="member-name">{{ member.name }}</span> |
|
|
|
@ -69,16 +114,25 @@ |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<el-empty v-if="!loading && recentGroups.length === 0" description="暂无群组" /> |
|
|
|
<el-empty |
|
|
|
|
|
|
|
v-if="!loading && recentGroups.length === 0" |
|
|
|
|
|
|
|
description="暂无群组" |
|
|
|
|
|
|
|
/> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</el-tab-pane> |
|
|
|
</el-tab-pane> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 组织架构 --> |
|
|
|
<!-- 组织架构 --> |
|
|
|
<el-tab-pane label="组织架构" name="organization"> |
|
|
|
<el-tab-pane label="组织架构" name="organization"> |
|
|
|
<div v-loading="loading" class="contact-list"> |
|
|
|
<div v-loading="loading" class="contact-list"> |
|
|
|
<el-tree ref="orgTree" :data="treeData" :props="{ label: 'name', children: 'children' }" |
|
|
|
<el-tree |
|
|
|
:highlight-current="true" node-key="id" :expand-on-click-node="false" |
|
|
|
ref="orgTree" |
|
|
|
@node-click="handleOrgNodeClick"> |
|
|
|
:data="treeData" |
|
|
|
|
|
|
|
:props="{ label: 'name', children: 'children' }" |
|
|
|
|
|
|
|
:highlight-current="true" |
|
|
|
|
|
|
|
node-key="id" |
|
|
|
|
|
|
|
:expand-on-click-node="false" |
|
|
|
|
|
|
|
@node-click="handleOrgNodeClick" |
|
|
|
|
|
|
|
> |
|
|
|
<template #default="{ node, data }"> |
|
|
|
<template #default="{ node, data }"> |
|
|
|
<div class="custom-tree-node"> |
|
|
|
<div class="custom-tree-node"> |
|
|
|
<!-- 组织节点 --> |
|
|
|
<!-- 组织节点 --> |
|
|
|
@ -88,19 +142,30 @@ |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
<!-- 全选节点 --> |
|
|
|
<!-- 全选节点 --> |
|
|
|
<template v-else-if="data.type === 'all'"> |
|
|
|
<template v-else-if="data.type === 'all'"> |
|
|
|
<el-checkbox :indeterminate="data.indeterminate" v-model="data.checkAll" |
|
|
|
<el-checkbox |
|
|
|
@change="handleOrgCheckAllChange(data)"> |
|
|
|
:indeterminate="data.indeterminate" |
|
|
|
|
|
|
|
v-model="data.checkAll" |
|
|
|
|
|
|
|
@change="handleOrgCheckAllChange(data)" |
|
|
|
|
|
|
|
> |
|
|
|
全选 |
|
|
|
全选 |
|
|
|
</el-checkbox> |
|
|
|
</el-checkbox> |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
<!-- 用户节点 --> |
|
|
|
<!-- 用户节点 --> |
|
|
|
<div v-else-if="data.type === 'user'" class="userline"> |
|
|
|
<div v-else-if="data.type === 'user'" class="userline"> |
|
|
|
<el-checkbox :value="isSelected(data.id)" @change="toggleSelect(data)" |
|
|
|
<el-checkbox |
|
|
|
:disabled="isSelectDisabled && !isSelected(data.id)"> |
|
|
|
:value="isSelected(data.id)" |
|
|
|
|
|
|
|
@change="toggleSelect(data)" |
|
|
|
|
|
|
|
:disabled="isSelectDisabled && !isSelected(data.id)" |
|
|
|
|
|
|
|
> |
|
|
|
<div class="member-item-label"> |
|
|
|
<div class="member-item-label"> |
|
|
|
<el-avatar :size="32" :src="$store.state.user.netConfig |
|
|
|
<el-avatar |
|
|
|
.MINIO_ENDPOINT_HTTPS + data.avatar |
|
|
|
:size="32" |
|
|
|
" icon="el-icon-user-solid" /> |
|
|
|
:src=" |
|
|
|
|
|
|
|
$store.state.user.netConfig |
|
|
|
|
|
|
|
.MINIO_ENDPOINT_HTTPS + data.avatar |
|
|
|
|
|
|
|
" |
|
|
|
|
|
|
|
icon="el-icon-user-solid" |
|
|
|
|
|
|
|
/> |
|
|
|
<span class="member-name">{{ data.name }}</span> |
|
|
|
<span class="member-name">{{ data.name }}</span> |
|
|
|
<span v-if="data.online" class="online-dot" /> |
|
|
|
<span v-if="data.online" class="online-dot" /> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
@ -119,35 +184,58 @@ |
|
|
|
</el-col> |
|
|
|
</el-col> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 右侧:已选人员 --> |
|
|
|
<!-- 右侧:已选人员 --> |
|
|
|
<el-col :span="12" style="height: 100%; display: flex; flex-direction: column"> |
|
|
|
<el-col |
|
|
|
|
|
|
|
:span="12" |
|
|
|
|
|
|
|
style="height: 100%; display: flex; flex-direction: column" |
|
|
|
|
|
|
|
> |
|
|
|
<div class="selected-header"> |
|
|
|
<div class="selected-header"> |
|
|
|
已选人员({{ selectedMembers.length }} |
|
|
|
已选人员({{ selectedMembers.length }} |
|
|
|
<template v-if="maxSelectCount > 0">/{{ maxSelectCount }}</template>) |
|
|
|
<template v-if="maxSelectCount > 0">/{{ maxSelectCount }}</template |
|
|
|
<span v-if="selectedMembers.length > 0" class="clear-btn" @click="clearAllSelected"> |
|
|
|
>) |
|
|
|
|
|
|
|
<span |
|
|
|
|
|
|
|
v-if="selectedMembers.length > 0" |
|
|
|
|
|
|
|
class="clear-btn" |
|
|
|
|
|
|
|
@click="clearAllSelected" |
|
|
|
|
|
|
|
> |
|
|
|
<i class="el-icon-close" /> |
|
|
|
<i class="el-icon-close" /> |
|
|
|
</span> |
|
|
|
</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="selected-list"> |
|
|
|
<div class="selected-list"> |
|
|
|
<div v-for="member in selectedMembers" :key="member.id" class="selected-item"> |
|
|
|
<div |
|
|
|
|
|
|
|
v-for="member in selectedMembers" |
|
|
|
|
|
|
|
:key="member.id" |
|
|
|
|
|
|
|
class="selected-item" |
|
|
|
|
|
|
|
> |
|
|
|
<el-avatar :size="40" :src="member.avatar" /> |
|
|
|
<el-avatar :size="40" :src="member.avatar" /> |
|
|
|
<span class="selected-name">{{ member.name }}</span> |
|
|
|
<span class="selected-name">{{ member.name }}</span> |
|
|
|
<span class="remove-btn" @click="removeSelected(member)"> |
|
|
|
<span class="remove-btn" @click="removeSelected(member)"> |
|
|
|
<i class="el-icon-close" /> |
|
|
|
<i class="el-icon-close" /> |
|
|
|
</span> |
|
|
|
</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<el-empty v-if="selectedMembers.length === 0" description="暂无选中人员" class="empty-tip" /> |
|
|
|
<el-empty |
|
|
|
|
|
|
|
v-if="selectedMembers.length === 0" |
|
|
|
|
|
|
|
description="暂无选中人员" |
|
|
|
|
|
|
|
class="empty-tip" |
|
|
|
|
|
|
|
/> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div v-if=" |
|
|
|
<div |
|
|
|
maxSelectCount > 0 && selectedMembers.length >= maxSelectCount |
|
|
|
v-if=" |
|
|
|
" class="max-tip"> |
|
|
|
maxSelectCount > 0 && selectedMembers.length >= maxSelectCount |
|
|
|
|
|
|
|
" |
|
|
|
|
|
|
|
class="max-tip" |
|
|
|
|
|
|
|
> |
|
|
|
已达到最大选择数量({{ maxSelectCount }}) |
|
|
|
已达到最大选择数量({{ maxSelectCount }}) |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</el-col> |
|
|
|
</el-col> |
|
|
|
</el-row> |
|
|
|
</el-row> |
|
|
|
<span slot="footer" class="dialog-footer"> |
|
|
|
<span slot="footer" class="dialog-footer"> |
|
|
|
<el-button @click="handleClose">取 消</el-button> |
|
|
|
<el-button @click="handleClose">取 消</el-button> |
|
|
|
<el-button type="primary" :loading="confirmLoading" :disabled="selectedMembers.length < minSelectCount" |
|
|
|
<el-button |
|
|
|
@click="confirmCreateGroup"> |
|
|
|
type="primary" |
|
|
|
|
|
|
|
:loading="confirmLoading" |
|
|
|
|
|
|
|
:disabled="selectedMembers.length < minSelectCount" |
|
|
|
|
|
|
|
@click="confirmCreateGroup" |
|
|
|
|
|
|
|
> |
|
|
|
确认 |
|
|
|
确认 |
|
|
|
</el-button> |
|
|
|
</el-button> |
|
|
|
</span> |
|
|
|
</span> |
|
|
|
@ -179,7 +267,7 @@ export default { |
|
|
|
default: 1, |
|
|
|
default: 1, |
|
|
|
}, |
|
|
|
}, |
|
|
|
confirmCallback: { |
|
|
|
confirmCallback: { |
|
|
|
type: Function, |
|
|
|
type: Function, |
|
|
|
default: null, |
|
|
|
default: null, |
|
|
|
}, |
|
|
|
}, |
|
|
|
}, |
|
|
|
}, |
|
|
|
@ -652,6 +740,7 @@ export default { |
|
|
|
handleClose(done) { |
|
|
|
handleClose(done) { |
|
|
|
this.clearAllSelected(); |
|
|
|
this.clearAllSelected(); |
|
|
|
this.searchText = ""; |
|
|
|
this.searchText = ""; |
|
|
|
|
|
|
|
this.visible = false; |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
// 确认创建群聊 |
|
|
|
// 确认创建群聊 |
|
|
|
|