增加个人办公模块

This commit is contained in:
2026-08-28 13:06:54 +08:00
parent 74ab6c4c6d
commit 576fea3770
27 changed files with 3370 additions and 59 deletions
@@ -0,0 +1,208 @@
<template>
<el-dialog
v-model="visible"
title="联系人详情"
width="560px"
@close="handleClose"
>
<div v-if="contact" class="detail-content">
<!-- 头部信息 -->
<div class="detail-header-card">
<el-avatar :size="56" :src="contact.avatar || ''" class="detail-avatar">
{{ contact.contact_name?.charAt(0) }}
</el-avatar>
<div class="detail-header-info">
<div class="detail-name-row">
<span class="detail-name">{{ contact.contact_name }}</span>
<el-tag :type="contact.contact_type === 1 ? 'primary' : 'info'" size="small">
{{ contact.contact_type === 1 ? '内部员工' : '外部联系人' }}
</el-tag>
<el-tag
v-if="contact.is_starred === 1"
type="warning"
size="small"
>
已收藏
</el-tag>
</div>
<div class="detail-sub" v-if="contact.position_title || contact.org_name || contact.dept_name">
<span v-if="contact.position_title">{{ contact.position_title }}</span>
<span v-if="contact.position_title && (contact.org_name || contact.dept_name)"> · </span>
<span v-if="contact.org_name || contact.dept_name">{{ contact.org_name || contact.dept_name }}</span>
</div>
<div class="detail-sub" v-if="contact.company_name">
{{ contact.company_name }}
</div>
</div>
</div>
<!-- 联系方式 -->
<div class="detail-section">
<h4>联系方式</h4>
<el-descriptions :column="1" border size="small">
<el-descriptions-item label="手机号">
<span v-if="contact.phone">
<a :href="'tel:' + contact.phone" class="contact-link">{{ contact.phone }}</a>
</span>
<span v-else class="empty-text">-</span>
</el-descriptions-item>
<el-descriptions-item label="办公电话">
<span v-if="contact.work_phone">
<a :href="'tel:' + contact.work_phone" class="contact-link">{{ contact.work_phone }}</a>
</span>
<span v-else class="empty-text">-</span>
</el-descriptions-item>
<el-descriptions-item label="邮箱">
<span v-if="contact.email">
<a :href="'mailto:' + contact.email" class="contact-link">{{ contact.email }}</a>
</span>
<span v-else class="empty-text">-</span>
</el-descriptions-item>
<el-descriptions-item label="微信号">
<span>{{ contact.wechat || '-' }}</span>
</el-descriptions-item>
</el-descriptions>
</div>
<!-- 其他信息 -->
<div class="detail-section">
<h4>其他信息</h4>
<el-descriptions :column="1" border size="small">
<el-descriptions-item label="性别">
{{ genderLabel(contact.gender) }}
</el-descriptions-item>
<el-descriptions-item label="部门">
{{ contact.org_name || contact.dept_name || '-' }}
</el-descriptions-item>
<el-descriptions-item label="地址">
{{ contact.address || '-' }}
</el-descriptions-item>
<el-descriptions-item label="备注">
{{ contact.remark || '-' }}
</el-descriptions-item>
<el-descriptions-item label="状态">
<el-tag :type="contact.status === 1 ? 'success' : 'danger'" size="small">
{{ contact.status === 1 ? '正常' : '停用' }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="创建时间">
{{ contact.create_time || '-' }}
</el-descriptions-item>
</el-descriptions>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleClose">关闭</el-button>
<el-button type="primary" @click="handleEdit">编辑</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
modelValue: { type: Boolean, default: false },
contact: { type: Object, default: null }
})
const emit = defineEmits(['update:modelValue', 'edit'])
const visible = computed({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val)
})
const genderLabel = (gender) => {
const map = { 1: '男', 2: '女' }
return map[gender] || '未知'
}
const handleEdit = () => {
emit('edit', props.contact)
}
const handleClose = () => {
visible.value = false
}
</script>
<style lang="less" scoped>
.detail-content {
max-height: 65vh;
overflow-y: auto;
}
.detail-header-card {
display: flex;
gap: 16px;
padding: 16px;
background: #f5f7fa;
border-radius: 8px;
margin-bottom: 20px;
}
.detail-avatar {
flex-shrink: 0;
background: #409eff;
color: #fff;
font-size: 22px;
}
.detail-header-info {
display: flex;
flex-direction: column;
justify-content: center;
gap: 6px;
}
.detail-name-row {
display: flex;
align-items: center;
gap: 8px;
}
.detail-name {
font-size: 18px;
font-weight: 600;
color: #303133;
}
.detail-sub {
font-size: 13px;
color: #606266;
}
.detail-section {
margin-bottom: 20px;
}
.detail-section h4 {
margin: 0 0 12px;
font-size: 14px;
font-weight: 600;
color: #303133;
}
.contact-link {
color: #409eff;
text-decoration: none;
}
.contact-link:hover {
text-decoration: underline;
}
.empty-text {
color: #c0c4cc;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 8px;
}
</style>