<template>
|
<div class="app-container">
|
<!-- 头部导航 -->
|
<!-- <div class="header">
|
<h2>企业通讯录管理</h2>
|
<p>管理个人、公共和单位的联系方式</p>
|
</div> -->
|
|
<!-- 标签页切换 -->
|
<el-tabs v-model="activeTab" @tab-change="handleTabChange" type="border-card">
|
<el-tab-pane label="个人通讯录" name="personal">
|
<div class="tab-content">
|
<!-- 搜索框 -->
|
<el-input
|
v-model="personalSearch.staffName"
|
placeholder="搜索联系人"
|
clearable
|
prefix-icon="Search"
|
class="search-input"
|
@keyup.enter="getPersonalContactsList"
|
/>
|
<el-button style="margin: 0 0 20px 20px;" type="primary" @click="showAddContactDialog=true">添加联系人</el-button>
|
<!-- 联系人列表 -->
|
<div class="contact-list">
|
<div
|
v-for="contact in personalContacts"
|
:key="contact.id"
|
class="contact-card"
|
@click="showContactDetail(contact)"
|
>
|
<div class="contact-avatar">{{ contact.staffName.charAt(0) }}</div>
|
<div class="contact-info">
|
<h4>{{ contact.staffName }}</h4>
|
<p>{{ contact.profession }} - {{ contact.postJob }}</p>
|
<div class="contact-phone">{{ contact.phone }}</div>
|
</div>
|
<div class="contact-actions">
|
<!-- <el-button
|
type="text"
|
icon="Phone"
|
@click.stop="callContact(contact)"
|
></el-button> -->
|
<el-button
|
type="text"
|
icon="Message"
|
@click.stop="messageContact(contact)"
|
></el-button>
|
<el-button
|
type="text"
|
icon="Delete"
|
@click.stop="removeFromPersonalContacts(contact.id)"
|
></el-button>
|
</div>
|
</div>
|
|
<!-- 空状态
|
<div v-if="personalContacts.length === 0 && !loading" class="empty-state">
|
<el-empty description="暂无联系人" />
|
<el-button type="primary" @click="showAddContactDialog=true">添加联系人</el-button>
|
</div> -->
|
</div>
|
</div>
|
</el-tab-pane>
|
|
<el-tab-pane label="公共通讯录" name="public">
|
<div class="tab-content">
|
<!-- 搜索框 -->
|
<el-input
|
v-model="publicSearch.staffName"
|
placeholder="搜索公共联系人"
|
clearable
|
prefix-icon="Search"
|
class="search-input"
|
@keyup.enter="getPublicContactsList"
|
/>
|
|
<!-- 联系人列表 publicContacts-->
|
<div class="contact-list">
|
<div
|
v-for="contact in EmployeeList"
|
:key="contact.id"
|
class="contact-card"
|
@click="showContactDetail(contact)"
|
>
|
<div class="contact-avatar">{{ contact.staffName.charAt(0) }}</div>
|
<div class="contact-info">
|
<h4>{{ contact.staffName }}</h4>
|
<p>{{ contact.postJob }} - {{ contact.profession }}</p>
|
<div class="contact-phone">{{ contact.phone }}</div>
|
</div>
|
<div class="contact-actions">
|
<!-- <el-button
|
type="text"
|
icon="Phone"
|
@click.stop="callContact(contact)"
|
></el-button> -->
|
<el-button
|
type="text"
|
icon="Message"
|
@click.stop="messageContact(contact)"
|
></el-button>
|
<el-button
|
type="text"
|
icon="Delete"
|
:type="isInPersonalContacts(contact.id) ? 'primary' : ''"
|
@click.stop="togglePersonalContact(contact)"
|
></el-button>
|
</div>
|
</div>
|
</div>
|
</div>
|
</el-tab-pane>
|
|
<el-tab-pane label="单位通讯录" name="company">
|
<div class="tab-content">
|
<div class="company-contacts-layout">
|
<!-- 左侧部门树 -->
|
<div class="department-tree">
|
<!-- <h3>部门结构</h3>
|
<el-tree
|
:data="departmentTree"
|
:props="{ label: 'deptName', children: 'children' }"
|
node-key="deptId"
|
ref="departmentTreeRef"
|
highlight-current
|
default-expand-all
|
@node-click="handleDepartmentClick"
|
/> -->
|
<el-col >
|
<div class="head-container">
|
<el-input
|
v-model="deptName"
|
placeholder="请输入部门名称"
|
clearable
|
prefix-icon="Search"
|
style="margin-bottom: 20px"
|
/>
|
</div>
|
<div class="head-container">
|
<el-tree
|
:data="departmentTree"
|
:props="{ label: 'label', children: 'children' }"
|
:expand-on-click-node="false"
|
:filter-node-method="filterNode"
|
ref="deptTreeRef"
|
node-key="id"
|
highlight-current
|
default-expand-all
|
@node-click="handleDepartmentClick"
|
/>
|
</div>
|
</el-col>
|
</div>
|
|
<!-- 右侧部门成员 -->
|
<div class="department-members">
|
<h3>{{ currentDepartment?.label || '全部成员' }}</h3>
|
<el-input
|
v-model="companySearch.staffName"
|
placeholder="搜索部门成员"
|
clearable
|
prefix-icon="Search"
|
class="search-input"
|
@keyup.enter="getCompanyContactsList"
|
/>
|
|
<div class="contact-list">
|
<div
|
v-for="contact in companyContacts"
|
:key="contact.id"
|
class="contact-card"
|
@click="showContactDetail(contact)"
|
>
|
<div class="contact-avatar">{{ contact.staffName.charAt(0) }}</div>
|
<div class="contact-info">
|
<h4>{{ contact.staffName }}</h4>
|
<p>{{ contact.profession }}</p>
|
<div class="contact-phone">{{ contact.phone }}</div>
|
</div>
|
<div class="contact-actions">
|
|
<el-button
|
type="text"
|
icon="Message"
|
@click.stop="messageContact(contact)"
|
></el-button>
|
<el-button
|
type="text"
|
icon="Delete"
|
:type="isInPersonalContacts(contact.id) ? 'primary' : ''"
|
@click.stop="togglePersonalContact(contact)"
|
></el-button>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</el-tab-pane>
|
</el-tabs>
|
|
<!-- 联系人详情弹窗 -->
|
<el-dialog
|
v-model="showDetailDialog"
|
title="联系人详情"
|
width="400px"
|
>
|
<div v-if="selectedContact" class="contact-detail">
|
<div class="detail-avatar">{{ selectedContact.staffName?.charAt(0) }}</div>
|
<h3>{{ selectedContact.staffName }}</h3>
|
<p class="detail-position">{{ selectedContact.profession }} - {{ selectedContact.postJob }}</p>
|
|
<div class="detail-info">
|
<div class="info-item">
|
<span class="label">编号:</span>
|
<span class="value">{{ selectedContact.staffNo }}</span>
|
</div>
|
<div class="info-item">
|
<span class="label">手机号码:</span>
|
<span class="value">{{ selectedContact.phone }}</span>
|
</div>
|
<div class="info-item">
|
<span class="label">邮箱:</span>
|
<span class="value">{{ selectedContact.sex }}</span>
|
</div>
|
<div class="info-item">
|
<span class="label">住址:</span>
|
<span class="value">{{ selectedContact.adress || '暂无' }}</span>
|
</div>
|
</div>
|
</div>
|
<template #footer>
|
<el-button @click="showDetailDialog = false">关闭</el-button>
|
<el-button
|
type="primary"
|
v-if="activeTab !== 'personal'"
|
@click="togglePersonalContact(selectedContact); showDetailDialog = false"
|
>
|
{{ isInPersonalContacts(selectedContact?.id) ? '从个人通讯录移除' : '添加到个人通讯录' }}
|
</el-button>
|
</template>
|
</el-dialog>
|
|
<!-- 添加联系人弹窗 -->
|
<el-dialog
|
v-model="showAddContactDialog"
|
title="添加联系人"
|
width="500px"
|
>
|
<el-form :model="addContactForm" ref="addContactFormRef" label-width="80px">
|
<!-- <el-form-item label="姓名" prop="name">
|
<el-input v-model="addContactForm.name" placeholder="请输入姓名" />
|
</el-form-item>
|
<el-form-item label="手机号码" prop="phone">
|
<el-input v-model="addContactForm.phone" placeholder="请输入手机号码" />
|
</el-form-item>
|
<el-form-item label="邮箱" prop="email">
|
<el-input v-model="addContactForm.email" placeholder="请输入邮箱" />
|
</el-form-item>
|
<el-form-item label="部门" prop="department">
|
<el-input v-model="addContactForm.department" placeholder="请输入部门" />
|
</el-form-item> -->
|
<el-form-item label="姓名" prop="name">
|
<!-- <select v-model="addContactForm.contactId">
|
<option v-for="item in EmployeeList" :key="item.id" :value="item.id">{{ item.staffName }}</option>
|
</select> -->
|
<el-select v-model="addContactForm.contactId" placeholder="请选择" style="width: 100%">
|
<el-option
|
v-for="option in EmployeeList"
|
:key="option.id"
|
:label="option.staffName"
|
:value="option.id"
|
/>
|
</el-select>
|
</el-form-item>
|
</el-form>
|
<template #footer>
|
<el-button @click="showAddContactDialog = false">取消</el-button>
|
<el-button type="primary" @click="addContact">确定</el-button>
|
</template>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, onMounted, reactive, computed } from 'vue'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
import {
|
getPersonalContacts,
|
addPersonalContact,
|
removePersonalContact,
|
getPublicContacts,
|
getCompanyContacts,
|
getDepartmentTree,
|
getEmployeeDetail
|
} from '@/api/collaborativeApproval/enterpriseBook.js'
|
import { getUserProfile } from '@/api/system/user.js'
|
import {staffJoinListPage} from "@/api/personnelManagement/onboarding.js";
|
import {
|
changeUserStatus,
|
listUser,
|
resetUserPwd,
|
delUser,
|
getUser,
|
updateUser,
|
addUser,
|
deptTreeSelect,
|
} from "@/api/system/user";
|
|
// 标签页状态
|
const activeTab = ref('personal')
|
const loading = ref(false)
|
const EmployeeList = ref([])
|
const page = reactive({
|
pageNum: 1,
|
pageSize: 10,
|
total: 0,
|
})
|
// 个人通讯录数据
|
const personalContacts = ref([])
|
const personalSearch = ref({
|
staffName: '',
|
})
|
|
// 公共通讯录数据
|
const publicContacts = ref([])
|
const publicSearch = ref({
|
staffName: '',
|
staffState: 1
|
})
|
|
// 单位通讯录数据
|
const companyContacts = ref([])
|
const companySearch = ref({
|
staffName: '',
|
staffState: 1
|
})
|
const departmentTree = ref([])
|
const departmentTreeRef = ref(null)
|
const currentDepartment = ref(null)
|
|
// 弹窗状态
|
const showDetailDialog = ref(false)
|
const showAddContactDialog = ref(false)
|
const selectedContact = ref(null)
|
|
// 添加联系人表单
|
const addContactForm = reactive({
|
contactId: '',
|
name: '',
|
phone: '',
|
email: '',
|
department: '',
|
position: ''
|
})
|
const addContactFormRef = ref(null)
|
|
// 初始化数据
|
onMounted(() => {
|
getEmployeeList()
|
getPersonalContactsList()
|
if (activeTab.value === 'public') {
|
getPublicContactsList()
|
} else if (activeTab.value === 'company') {
|
getDepartmentTreeData()
|
getCompanyContactsList()
|
}
|
})
|
|
// 处理标签页切换
|
const handleTabChange = (tabName) => {
|
if (tabName === 'public') {
|
getPublicContactsList()
|
} else if (tabName === 'company') {
|
getDepartmentTreeData()
|
getCompanyContactsList()
|
}
|
}
|
|
// 获取个人通讯录列表
|
const getPersonalContactsList = async () => {
|
loading.value = true
|
getPersonalContacts(page,personalSearch.value).then(res => {
|
personalContacts.value = res.data.records
|
})
|
loading.value = false
|
}
|
|
// 获取公共通讯录列表
|
const getPublicContactsList = async () => {
|
loading.value = true
|
getEmployeeList()
|
// publicContacts.value = generateMockPublicContacts()
|
loading.value = false
|
}
|
//获取员工列表
|
const getEmployeeList = async () => {
|
staffJoinListPage(publicSearch.value).then(res => {
|
console.log(res.data.records)
|
EmployeeList.value = res.data.records
|
}).catch(err => {})
|
}
|
// 获取单位通讯录列表
|
const getCompanyContactsList = async () => {
|
loading.value = true
|
staffJoinListPage(companySearch.value).then(res => {
|
// console.log(res.data.records)
|
companyContacts.value = res.data.records
|
}).catch(err => {})
|
|
loading.value = false
|
loading.value = false
|
// }
|
}
|
|
// 获取部门树结构
|
const getDepartmentTreeData = async () => {
|
deptTreeSelect().then((response) => {
|
// console.log("Tree",response.data)
|
departmentTree.value = response.data;
|
// enabledDeptOptions.value = filterDisabledDept(
|
// JSON.parse(JSON.stringify(response.data))
|
// );
|
});
|
}
|
// /** 过滤禁用的部门 */
|
// function filterDisabledDept(deptList) {
|
// return deptList.filter((dept) => {
|
// if (dept.disabled) {
|
// return false;
|
// }
|
// if (dept.children && dept.children.length) {
|
// dept.children = filterDisabledDept(dept.children);
|
// }
|
// return true;
|
// });
|
// }
|
// 处理部门点击
|
const handleDepartmentClick = (data) => {
|
// console.log("点击",data)
|
companySearch.value = {
|
...companySearch.value,
|
deptId: data.id,
|
}
|
// currentDepartment.value = data.id
|
// 获取该部门的成员列表
|
|
getCompanyContactsList()
|
}
|
|
// 显示联系人详情
|
const showContactDetail = async (contact) => {
|
selectedContact.value = contact
|
showDetailDialog.value = true
|
}
|
|
// 拨打电话
|
const callContact = (contact) => {
|
ElMessage.info(`正在拨打 ${contact.name} 的电话: ${contact.phone}`)
|
}
|
|
// 发送消息
|
const messageContact = (contact) => {
|
ElMessage.info(`正在发送消息给 ${contact.name}`)
|
}
|
|
|
// 添加联系人
|
const addContact = async () => {
|
|
try {
|
// 表单验证
|
// if (!addContactForm.name || !addContactForm.phone) {
|
// ElMessage.warning('请填写姓名和手机号码')
|
// return
|
// }
|
|
const res = await addPersonalContact(addContactForm)
|
if (res.code === 200) {
|
ElMessage.success('添加成功')
|
showAddContactDialog.value = false
|
getPersonalContactsList()
|
// 重置表单
|
Object.keys(addContactForm).forEach(key => {
|
addContactForm[key] = ''
|
})
|
}
|
} catch (error) {
|
ElMessage.error('添加失败')
|
// 模拟添加成功
|
personalContacts.value.push({
|
...addContactForm,
|
id: Date.now(),
|
createTime: new Date().toISOString()
|
})
|
ElMessage.success('添加成功')
|
showAddContactDialog.value = false
|
// 重置表单
|
Object.keys(addContactForm).forEach(key => {
|
addContactForm[key] = ''
|
})
|
}
|
}
|
|
// 从个人通讯录移除
|
const removeFromPersonalContacts = async (contactId) => {
|
ElMessageBox.confirm(
|
'确定要从个人通讯录中移除该联系人吗?',
|
'提示',
|
{
|
confirmButtonText: '确定',
|
cancelButtonText: '取消',
|
type: 'warning'
|
}
|
).then(async () => {
|
try {
|
const res = await removePersonalContact(contactId)
|
if (res.code === 200) {
|
ElMessage.success('移除成功')
|
getPersonalContactsList()
|
}
|
} catch (error) {
|
ElMessage.error('移除失败')
|
// 模拟移除成功
|
// personalContacts.value = personalContacts.value.filter(item => item.id !== contactId)
|
ElMessage.success('移除成功')
|
}
|
})
|
}
|
|
// 切换个人通讯录
|
const togglePersonalContact = async (contact) => {
|
const isInPersonal = isInPersonalContacts(contact.id)
|
const contactId = contact.id
|
if (isInPersonal) {
|
// 从个人通讯录移除
|
//根据contactId查找personalContacts中对应的项,然后删除该项
|
const index = personalContacts.value.findIndex(item => item.contactId === contactId)
|
const personId = personalContacts.value[index].id
|
// console.log(personId)
|
await removeFromPersonalContacts(personId)
|
} else {
|
// 添加到个人通讯录
|
try {
|
const res = await addPersonalContact({contactId: contactId})
|
if (res.code === 200) {
|
ElMessage.success('添加成功')
|
getPersonalContactsList()
|
}
|
} catch (error) {
|
ElMessage.error('添加失败')
|
// 模拟添加成功
|
// personalContacts.value.push({
|
// ...contact,
|
// id: contact.id || Date.now(),
|
// createTime: new Date().toISOString()
|
// })
|
// ElMessage.success('添加成功')
|
}
|
}
|
}
|
|
// 检查是否在个人通讯录中
|
const isInPersonalContacts = (contactId) => {
|
return personalContacts.value.some(item => item.contactId === contactId)
|
}
|
|
// 生成模拟部门树数据
|
const generateMockDepartmentTree = () => {
|
return [
|
{
|
deptId: 1,
|
deptName: '技术部',
|
children: [
|
{
|
deptId: 101,
|
deptName: '前端组'
|
},
|
{
|
deptId: 102,
|
deptName: '后端组'
|
},
|
{
|
deptId: 103,
|
deptName: '测试组'
|
}
|
]
|
},
|
{
|
deptId: 2,
|
deptName: '产品部'
|
},
|
{
|
deptId: 3,
|
deptName: '人事部'
|
},
|
{
|
deptId: 4,
|
deptName: '财务部'
|
}
|
]
|
}
|
|
// 生成模拟单位通讯录数据
|
// const generateMockCompanyContacts = (deptName) => {
|
// const allContacts = getEmployeeList()
|
|
// if (deptName) {
|
// return allContacts.filter(contact => contact.postJob === deptName)
|
// }
|
// return allContacts
|
// }
|
|
</script>
|
|
<style scoped>
|
.header {
|
margin-bottom: 20px;
|
padding: 15px;
|
background: #f5f7fa;
|
border-radius: 8px;
|
}
|
|
.header h2 {
|
margin: 0 0 5px 0;
|
color: #303133;
|
}
|
|
.header p {
|
margin: 0;
|
color: #909399;
|
font-size: 14px;
|
}
|
|
.tab-content {
|
padding: 15px;
|
background: #fff;
|
border-radius: 8px;
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
}
|
|
.search-input {
|
margin-bottom: 20px;
|
width: 300px;
|
}
|
|
.contact-list {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 15px;
|
}
|
|
.contact-card {
|
display: flex;
|
align-items: center;
|
padding: 15px;
|
width: 500px;
|
background: #f8f9fa;
|
border-radius: 8px;
|
cursor: pointer;
|
transition: all 0.3s;
|
}
|
|
.contact-card:hover {
|
background: #e9ecef;
|
transform: translateY(-2px);
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
}
|
|
.contact-avatar {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
width: 48px;
|
height: 48px;
|
background: #409eff;
|
color: #fff;
|
font-size: 20px;
|
font-weight: bold;
|
border-radius: 50%;
|
margin-right: 15px;
|
}
|
|
.contact-info {
|
flex: 1;
|
}
|
|
.contact-info h4 {
|
margin: 0 0 5px 0;
|
color: #303133;
|
font-size: 16px;
|
}
|
|
.contact-info p {
|
margin: 0 0 5px 0;
|
color: #606266;
|
font-size: 14px;
|
}
|
|
.contact-phone {
|
color: #409eff;
|
font-size: 14px;
|
}
|
|
.contact-actions {
|
display: flex;
|
gap: 5px;
|
}
|
|
.empty-state {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
padding: 60px 20px;
|
color: #909399;
|
}
|
|
.company-contacts-layout {
|
display: flex;
|
gap: 20px;
|
}
|
|
.department-tree {
|
width: 250px;
|
padding: 15px;
|
background: #f8f9fa;
|
border-radius: 8px;
|
}
|
|
.department-tree h3 {
|
margin: 0 0 15px 0;
|
padding-bottom: 10px;
|
border-bottom: 1px solid #e4e7ed;
|
color: #303133;
|
font-size: 16px;
|
}
|
|
.department-members {
|
flex: 1;
|
}
|
|
.department-members h3 {
|
margin: 0 0 15px 0;
|
color: #303133;
|
font-size: 16px;
|
}
|
|
.contact-detail {
|
text-align: center;
|
}
|
|
.detail-avatar {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
width: 80px;
|
height: 80px;
|
background: #409eff;
|
color: #fff;
|
font-size: 32px;
|
font-weight: bold;
|
border-radius: 50%;
|
margin: 0 auto 20px;
|
}
|
|
.contact-detail h3 {
|
margin: 0 0 10px 0;
|
color: #303133;
|
font-size: 20px;
|
}
|
|
.detail-position {
|
margin: 0 0 30px 0;
|
color: #606266;
|
font-size: 14px;
|
}
|
|
.detail-info {
|
text-align: left;
|
}
|
|
.info-item {
|
margin-bottom: 15px;
|
}
|
|
.info-item .label {
|
display: inline-block;
|
width: 100px;
|
color: #909399;
|
font-size: 14px;
|
}
|
|
.info-item .value {
|
color: #303133;
|
font-size: 14px;
|
}
|
</style>
|