CRM:完善联系人的编辑、详情

pull/392/head
YunaiV 2024-02-20 23:31:52 +08:00
parent 094b1925d6
commit 08bb022cb5
7 changed files with 202 additions and 222 deletions

View File

@ -2,29 +2,34 @@ import request from '@/config/axios'
import { TransferReqVO } from '@/api/crm/customer'
export interface ContactVO {
name: string
nextTime: Date
mobile: string
telephone: string
email: string
post: string
customerId: number
detailAddress: string
remark: string
ownerUserId: string
lastTime: Date
id: number
parentId: number
qq: number
wechat: string
sex: number
master: boolean
creatorName: string
updateTime?: Date
createTime?: Date
customerName: string
areaName: string
ownerUserName: string
id: number // 编号
name: string // 联系人名称
customerId: number // 客户编号
customerName?: string // 客户名称
contactLastTime: Date // 最后跟进时间
contactLastContent: string // 最后跟进内容
contactNextTime: Date // 下次联系时间
ownerUserId: number // 负责人的用户编号
ownerUserName?: string // 负责人的用户名称
ownerUserDept?: string // 负责人的部门名称
mobile: string // 手机号
telephone: string // 电话
qq: string // QQ
wechat: string // wechat
email: string // email
areaId: number // 所在地
areaName?: string // 所在地名称
detailAddress: string // 详细地址
sex: number // 性别
master: boolean // 是否主联系人
post: string // 职务
parentId: number // 上级联系人编号
parentName?: string // 上级联系人名称
remark: string // 备注
creator: string // 创建人
creatorName?: string // 创建人名称
createTime: Date // 创建时间
updateTime: Date // 更新时间
}
export interface ContactBusinessReqVO {

View File

@ -33,7 +33,7 @@
ref="permissionListRef"
:biz-id="clue.id!"
:biz-type="BizTypeEnum.CRM_CLUE"
:show-action="!permissionListRef?.isPool || false"
:show-action="true"
@quit-team="close"
/>
</el-tab-pane>

View File

@ -1,28 +1,27 @@
<template>
<Dialog v-model="dialogVisible" :title="dialogTitle" :width="820">
<Dialog v-model="dialogVisible" :title="dialogTitle">
<el-form
ref="formRef"
v-loading="formLoading"
:model="formData"
:rules="formRules"
label-width="110px"
label-width="100px"
>
<el-row :gutter="20">
<el-row>
<el-col :span="12">
<el-form-item label="姓名" prop="name">
<el-input v-model="formData.name" input-style="width:190px;" placeholder="请输入姓名" />
<el-form-item label="联系人姓名" prop="name">
<el-input v-model="formData.name" placeholder="请输入姓名" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="负责人" prop="ownerUserId">
<el-select
v-model="formData.ownerUserId"
lable-key="nickname"
placeholder="请选择负责人"
value-key="id"
:disabled="formType !== 'create'"
class="w-1/1"
>
<el-option
v-for="item in userList"
v-for="item in userOptions"
:key="item.id"
:label="item.nickname"
:value="item.id"
@ -33,13 +32,8 @@
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="客户名称" prop="customerName">
<el-select
v-model="formData.customerId"
lable-key="name"
placeholder="请选择客户"
value-key="id"
>
<el-form-item label="客户名称" prop="customerId">
<el-select v-model="formData.customerId" placeholder="请选择客户" class="w-1/1">
<el-option
v-for="item in customerList"
:key="item.id"
@ -50,113 +44,41 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="性别" prop="sex">
<el-select v-model="formData.sex" placeholder="请选择">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
<el-form-item label="手机" prop="mobile">
<el-input v-model="formData.mobile" placeholder="请输入手机" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="手机号" prop="mobile">
<el-input
v-model="formData.mobile"
input-style="width:190px;"
placeholder="请输入手机号"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="电话" prop="telephone">
<el-input v-model="formData.telephone" placeholder="请输入电话" style="width: 215px" />
<el-input v-model="formData.telephone" placeholder="请输入电话" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input
v-model="formData.email"
input-style="width:190px;"
placeholder="请输入邮箱"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="QQ" prop="qq">
<el-input v-model="formData.qq" placeholder="请输入QQ" style="width: 215px" />
<el-input v-model="formData.email" placeholder="请输入邮箱" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="微信" prop="wechat">
<el-input
v-model="formData.wechat"
input-style="width:190px;"
placeholder="请输入微信"
/>
<el-input v-model="formData.wechat" placeholder="请输入微信" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="下次联系时间" prop="contactNextTime">
<el-date-picker
v-model="formData.contactNextTime"
placeholder="选择下次联系时间"
type="datetime"
value-format="x"
/>
<el-form-item label="QQ" prop="qq">
<el-input v-model="formData.qq" placeholder="请输入 QQ" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="所在地" prop="areaId">
<el-tree-select
v-model="formData.areaId"
:data="areaList"
:props="defaultProps"
:render-after-expand="true"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="地址" prop="detailAddress">
<el-input
v-model="formData.detailAddress"
input-style="width:190px;"
placeholder="请输入地址"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="直属上级" prop="parentId">
<el-select v-model="formData.parentId" placeholder="请选择">
<el-option
v-for="item in allContactList"
:key="item.id"
:disabled="item.id == formData.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="职位" prop="post">
<el-input v-model="formData.post" input-style="width:190px;" placeholder="请输入职位" />
<el-input v-model="formData.post" placeholder="请输入职位" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="关键决策人" prop="master" style="width: 400px">
<el-radio-group v-model="formData.master">
@ -172,9 +94,66 @@
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-col :span="12">
<el-form-item label="性别" prop="sex">
<el-select v-model="formData.sex" placeholder="请选择" class="w-1/1">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="直属上级" prop="parentId">
<el-select v-model="formData.parentId" placeholder="请选择直属上级" class="w-1/1">
<el-option
v-for="item in contactList"
:key="item.id"
:disabled="item.id == formData.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="地址" prop="areaId">
<el-cascader
v-model="formData.areaId"
:options="areaList"
:props="defaultProps"
class="w-1/1"
clearable
filterable
placeholder="请选择城市"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="详细地址" prop="detailAddress">
<el-input v-model="formData.detailAddress" placeholder="请输入详细地址" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="下次联系时间" prop="contactNextTime">
<el-date-picker
v-model="formData.contactNextTime"
placeholder="选择下次联系时间"
type="datetime"
value-format="x"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入备注" />
<el-input type="textarea" v-model="formData.remark" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
@ -192,6 +171,7 @@ import * as UserApi from '@/api/system/user'
import * as CustomerApi from '@/api/crm/customer'
import * as AreaApi from '@/api/system/area'
import { defaultProps } from '@/utils/tree'
import { useUserStore } from '@/store/modules/user'
const { t } = useI18n() //
const message = useMessage() //
@ -202,25 +182,23 @@ const formLoading = ref(false) // 表单的加载中1修改时的数据加
const formType = ref('') // create - update -
const areaList = ref([]) //
const formData = ref({
id: undefined,
name: undefined,
customerId: undefined,
contactNextTime: undefined,
ownerUserId: 0,
mobile: undefined,
telephone: undefined,
email: undefined,
customerId: undefined,
customerName: undefined,
detailAddress: undefined,
remark: undefined,
ownerUserId: undefined,
lastTime: undefined,
id: undefined,
parentId: undefined,
name: undefined,
post: undefined,
qq: undefined,
wechat: undefined,
email: undefined,
areaId: undefined,
detailAddress: undefined,
sex: undefined,
master: false,
areaId: undefined
post: undefined,
parentId: undefined,
remark: undefined
})
const formRules = reactive({
name: [{ required: true, message: '姓名不能为空', trigger: 'blur' }],
@ -229,10 +207,10 @@ const formRules = reactive({
})
const formRef = ref() // Ref
const ownerUserList = ref<any[]>([])
const userList = ref<UserApi.UserVO[]>([]) //
const userOptions = ref<UserApi.UserVO[]>([]) //
// TODO
const customerList = ref<CustomerApi.CustomerVO[]>([]) //
const allContactList = ref<ContactApi.ContactVO[]>([]) //
const contactList = ref<ContactApi.ContactVO[]>([]) //
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
@ -240,10 +218,6 @@ const open = async (type: string, id?: number) => {
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
allContactList.value = await ContactApi.getSimpleContactList()
userList.value = await UserApi.getSimpleUserList()
customerList.value = await CustomerApi.getCustomerSimpleList()
areaList.value = await AreaApi.getAreaTree()
//
if (id) {
formLoading.value = true
@ -253,13 +227,22 @@ const open = async (type: string, id?: number) => {
formLoading.value = false
}
}
contactList.value = await ContactApi.getSimpleContactList()
customerList.value = await CustomerApi.getCustomerSimpleList()
//
areaList.value = await AreaApi.getAreaTree()
//
userOptions.value = await UserApi.getSimpleUserList()
//
if (formType.value === 'create') {
formData.value.ownerUserId = useUserStore().getUser.id
}
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
// owerSelectValue(ownerUserList)
//
if (!formRef) return
const valid = await formRef.value.validate()
@ -285,25 +268,24 @@ const submitForm = async () => {
/** 重置表单 */
const resetForm = () => {
// TODO zynaide
formData.value = {
id: undefined,
name: undefined,
customerId: undefined,
contactNextTime: undefined,
ownerUserId: 0,
mobile: undefined,
telephone: undefined,
email: undefined,
customerId: undefined,
detailAddress: undefined,
remark: undefined,
ownerUserId: undefined,
lastTime: undefined,
id: undefined,
parentId: undefined,
name: undefined,
post: undefined,
qq: undefined,
wechat: undefined,
email: undefined,
areaId: undefined,
detailAddress: undefined,
sex: undefined,
master: false
master: false,
post: undefined,
parentId: undefined,
remark: undefined
}
formRef.value?.resetFields()
ownerUserList.value = []

View File

@ -16,17 +16,11 @@
</div>
<ContentWrap class="mt-10px">
<el-descriptions :column="5" direction="vertical">
<el-descriptions-item label="客户">
{{ contact.customerName }}
</el-descriptions-item>
<el-descriptions-item label="职务">
{{ contact.post }}
</el-descriptions-item>
<el-descriptions-item label="手机">
{{ contact.mobile }}
</el-descriptions-item>
<el-descriptions-item label="客户名称">{{ contact.customerName }}</el-descriptions-item>
<el-descriptions-item label="职务">{{ contact.post }}</el-descriptions-item>
<el-descriptions-item label="手机">{{ contact.mobile }}</el-descriptions-item>
<el-descriptions-item label="创建时间">
{{ contact.createTime ? formatDate(contact.createTime) : '空' }}
{{ formatDate(contact.createTime) }}
</el-descriptions-item>
</el-descriptions>
</ContentWrap>

View File

@ -6,60 +6,49 @@
<span class="text-base font-bold">基本信息</span>
</template>
<el-descriptions :column="4">
<el-descriptions-item label="姓名">
{{ contact.name }}
<el-descriptions-item label="姓名">{{ contact.name }}</el-descriptions-item>
<el-descriptions-item label="客户名称">{{ contact.customerName }}</el-descriptions-item>
<el-descriptions-item label="手机">{{ contact.mobile }}</el-descriptions-item>
<el-descriptions-item label="电话">{{ contact.telephone }}</el-descriptions-item>
<el-descriptions-item label="邮箱">{{ contact.email }}</el-descriptions-item>
<el-descriptions-item label="QQ">{{ contact.qq }}</el-descriptions-item>
<el-descriptions-item label="微信">{{ contact.wechat }}</el-descriptions-item>
<el-descriptions-item label="地址">
{{ contact.areaName }} {{ contact.detailAddress }}
</el-descriptions-item>
<el-descriptions-item label="客户">
{{ contact.customerName }}
</el-descriptions-item>
<el-descriptions-item label="手机">
{{ contact.mobile }}
</el-descriptions-item>
<el-descriptions-item label="座机">
{{ contact.telephone }}
</el-descriptions-item>
<el-descriptions-item label="邮箱">
{{ contact.email }}
</el-descriptions-item>
<el-descriptions-item label="QQ">
{{ contact.qq }}
</el-descriptions-item>
<el-descriptions-item label="微信">
{{ contact.wechat }}
</el-descriptions-item>
<el-descriptions-item label="下次联系时间">
{{ contact.nextTime ? formatDate(contact.nextTime) : '空' }}
</el-descriptions-item>
<el-descriptions-item label="所在地">
{{ contact.areaName }}
</el-descriptions-item>
<el-descriptions-item label="详细地址">
{{ contact.detailAddress }}
<el-descriptions-item label="职务">{{ contact.post }}</el-descriptions-item>
<el-descriptions-item label="直属上级">{{ contact.parentName }}</el-descriptions-item>
<el-descriptions-item label="关键决策人">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="contact.master" />
</el-descriptions-item>
<el-descriptions-item label="性别">
<dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="contact.sex" />
</el-descriptions-item>
<el-descriptions-item label="备注">
{{ contact.remark }}
<el-descriptions-item label="下次联系时间">
{{ formatDate(contact.contactNextTime) }}
</el-descriptions-item>
<el-descriptions-item label="备注">{{ contact.remark }}</el-descriptions-item>
</el-descriptions>
</el-collapse-item>
<el-collapse-item name="systemInfo">
<template #title>
<span class="text-base font-bold">系统信息</span>
</template>
<el-descriptions :column="2">
<el-descriptions-item label="负责人">
{{ contact.ownerUserName }}
<el-descriptions :column="4">
<el-descriptions-item label="负责人">{{ contact.ownerUserName }}</el-descriptions-item>
<el-descriptions-item label="最后跟进记录">
{{ contact.contactLastContent }}
</el-descriptions-item>
<el-descriptions-item label="创建人">
{{ contact.creatorName }}
<el-descriptions-item label="最后跟进时间">
{{ formatDate(contact.contactLastTime) }}
</el-descriptions-item>
<el-descriptions-item label="">&nbsp;</el-descriptions-item>
<el-descriptions-item label="创建人">{{ contact.creatorName }}</el-descriptions-item>
<el-descriptions-item label="创建时间">
{{ contact.createTime ? formatDate(contact.createTime) : '空' }}
{{ formatDate(contact.createTime) }}
</el-descriptions-item>
<el-descriptions-item label="更新时间">
{{ contact.updateTime ? formatDate(contact.updateTime) : '空' }}
{{ formatDate(contact.updateTime) }}
</el-descriptions-item>
</el-descriptions>
</el-collapse-item>

View File

@ -9,6 +9,9 @@
</ContactDetailsHeader>
<el-col>
<el-tabs>
<el-tab-pane label="跟进记录">
<FollowUpList :biz-id="contactId" :biz-type="BizTypeEnum.CRM_CONTACT" />
</el-tab-pane>
<el-tab-pane label="详细资料">
<ContactDetailsInfo :contact="contact" />
</el-tab-pane>
@ -20,7 +23,7 @@
ref="permissionListRef"
:biz-id="contact.id!"
:biz-type="BizTypeEnum.CRM_CONTACT"
:show-action="!permissionListRef?.isPool || false"
:show-action="true"
@quit-team="close"
/>
</el-tab-pane>
@ -34,8 +37,8 @@
</el-tabs>
</el-col>
<!-- 表单弹窗添加/修改 -->
<ContactForm ref="formRef" @success="getContactData(contact.id)" />
<CrmTransferForm ref="crmTransferFormRef" @success="close" />
<ContactForm ref="formRef" @success="getContact(contact.id)" />
<CrmTransferForm ref="transferFormRef" @success="close" />
</template>
<script lang="ts" setup>
import { useTagsViewStore } from '@/store/modules/tagsView'
@ -49,18 +52,19 @@ import { OperateLogV2VO } from '@/api/system/operatelog'
import { getOperateLogPage } from '@/api/crm/operateLog'
import ContactForm from '@/views/crm/contact/ContactForm.vue'
import CrmTransferForm from '@/views/crm/permission/components/TransferForm.vue'
import FollowUpList from '@/views/crm/followup/index.vue'
defineOptions({ name: 'CrmContactDetail' })
const route = useRoute()
const message = useMessage()
const id = Number(route.params.id) //
const contactId = ref(0) // 线
const loading = ref(true) //
const contact = ref<ContactApi.ContactVO>({} as ContactApi.ContactVO) //
const permissionListRef = ref<InstanceType<typeof PermissionList>>() // Ref
/** 获取详情 */
const getContactData = async (id: number) => {
const getContact = async (id: number) => {
loading.value = true
try {
contact.value = await ContactApi.getContact(id)
@ -77,9 +81,9 @@ const openForm = (type: string, id?: number) => {
}
/** 联系人转移 */
const crmTransferFormRef = ref<InstanceType<typeof CrmTransferForm>>() // ref
const transferFormRef = ref<InstanceType<typeof CrmTransferForm>>() // ref
const transfer = () => {
crmTransferFormRef.value?.open('联系人转移', contact.value.id, ContactApi.transferContact)
transferFormRef.value?.open('联系人转移', contact.value.id, ContactApi.transferContact)
}
/** 获取操作日志 */
@ -96,19 +100,21 @@ const getOperateLog = async (contactId: number) => {
}
/** 关闭窗口 */
const { delView } = useTagsViewStore() //
const { currentRoute } = useRouter() //
const close = () => {
delView(unref(currentRoute))
}
/** 初始化 */
const { delView } = useTagsViewStore() //
const { currentRoute } = useRouter() //
const { params } = useRoute()
onMounted(async () => {
if (!id) {
if (!params.id) {
message.warning('参数错误,联系人不能为空!')
close()
return
}
await getContactData(id)
contactId.value = params.id as unknown as number
await getContact(contactId.value)
})
</script>

View File

@ -53,15 +53,6 @@
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="QQ" prop="qq">
<el-input
v-model="queryParams.qq"
class="!w-240px"
clearable
placeholder="请输入QQ"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="微信" prop="wechat">
<el-input
v-model="queryParams.wechat"
@ -109,6 +100,11 @@
<!-- 列表 -->
<ContentWrap>
<el-tabs v-model="activeName" @tab-click="handleTabClick">
<el-tab-pane label="我负责的" name="1" />
<el-tab-pane label="我参与的" name="2" />
<el-tab-pane label="下属负责的" name="3" />
</el-tabs>
<el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true">
<el-table-column align="center" fixed="left" label="联系人姓名" prop="name" width="160">
<template #default="scope">
@ -224,6 +220,7 @@ import * as ContactApi from '@/api/crm/contact'
import ContactForm from './ContactForm.vue'
import { DICT_TYPE } from '@/utils/dict'
import * as CustomerApi from '@/api/crm/customer'
import { TabsPaneContext } from 'element-plus'
defineOptions({ name: 'CrmContact' })
@ -237,16 +234,17 @@ const customerList = ref<CustomerApi.CustomerVO[]>([]) // 客户列表
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
sceneType: '1', // activeName
mobile: undefined,
telephone: undefined,
email: undefined,
customerId: undefined,
name: undefined,
qq: undefined,
wechat: undefined
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const activeName = ref('1') // tab
/** 查询列表 */
const getList = async () => {
@ -272,6 +270,12 @@ const resetQuery = () => {
handleQuery()
}
/** tab 切换 */
const handleTabClick = (tab: TabsPaneContext) => {
queryParams.sceneType = tab.paneName
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {