CRM:优化客户的列表、编辑的样式

pull/394/head
YunaiV 2024-02-20 09:35:48 +08:00
parent 04a42bc6d4
commit ac9a77e6e4
5 changed files with 130 additions and 177 deletions

View File

@ -1,36 +1,33 @@
import request from '@/config/axios' import request from '@/config/axios'
export interface CustomerVO { export interface CustomerVO {
id?: number id: number // 编号
name: string name: string // 客户名称
industryId: number followUpStatus: boolean // 跟进状态
level: number contactLastTime: Date // 最后跟进时间
source: number contactLastContent: string // 最后跟进内容
followUpStatus?: boolean contactNextTime: Date // 下次联系时间
ownerUserId: number // 负责人的用户编号
ownerUserName?: string // 负责人的用户名称
ownerUserDept?: string // 负责人的部门名称
lockStatus?: boolean lockStatus?: boolean
dealStatus?: boolean dealStatus?: boolean
mobile: string mobile: string // 手机号
telephone: string telephone: string // 电话
website: string qq: string // QQ
qq: string wechat: string // wechat
wechat: string email: string // email
email: string areaId: number // 所在地
description: string areaName?: string // 所在地名称
remark: string detailAddress: string // 详细地址
ownerUserId?: number industryId: number // 所属行业
ownerUserName?: string level: number // 客户等级
ownerUserDept?: string source: number // 客户来源
roUserIds?: string remark: string // 备注
rwUserIds?: string creator: string // 创建人
areaId?: number creatorName?: string // 创建人名称
areaName?: string createTime: Date // 创建时间
detailAddress: string updateTime: Date // 更新时间
contactLastTime?: Date
contactNextTime: Date
createTime?: Date
updateTime?: Date
creator?: string
creatorName?: string
} }
// 查询客户列表 // 查询客户列表

View File

@ -29,7 +29,7 @@
<!-- 列表 --> <!-- 列表 -->
<ContentWrap> <ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="线索名称" align="center" prop="name" fixed="left" width="120"> <el-table-column label="线索名称" align="center" prop="name" fixed="left" width="160">
<template #default="scope"> <template #default="scope">
<el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)">
{{ scope.row.name }} {{ scope.row.name }}
@ -41,7 +41,7 @@
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" /> <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="手机" align="center" prop="mobile" width="120" /> <el-table-column label="手机" align="center" prop="mobile" width="120" />
<el-table-column label="电话" align="center" prop="telephone" width="130" /> <el-table-column label="电话" align="center" prop="telephone" width="130" />
<el-table-column label="邮箱" align="center" prop="email" width="180" /> <el-table-column label="邮箱" align="center" prop="email" width="180" />
<el-table-column label="地址" align="center" prop="detailAddress" width="180" /> <el-table-column label="地址" align="center" prop="detailAddress" width="180" />

View File

@ -68,7 +68,7 @@
<el-tab-pane label="下属负责的" name="3" /> <el-tab-pane label="下属负责的" name="3" />
</el-tabs> </el-tabs>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="线索名称" align="center" prop="name" fixed="left" width="120"> <el-table-column label="线索名称" align="center" prop="name" fixed="left" width="160">
<template #default="scope"> <template #default="scope">
<el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)">
{{ scope.row.name }} {{ scope.row.name }}
@ -80,7 +80,7 @@
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" /> <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="手机" align="center" prop="mobile" width="120" /> <el-table-column label="手机" align="center" prop="mobile" width="120" />
<el-table-column label="电话" align="center" prop="telephone" width="130" /> <el-table-column label="电话" align="center" prop="telephone" width="130" />
<el-table-column label="邮箱" align="center" prop="email" width="180" /> <el-table-column label="邮箱" align="center" prop="email" width="180" />
<el-table-column label="地址" align="center" prop="detailAddress" width="180" /> <el-table-column label="地址" align="center" prop="detailAddress" width="180" />

View File

@ -13,23 +13,9 @@
<el-input v-model="formData.name" placeholder="请输入客户名称" /> <el-input v-model="formData.name" placeholder="请输入客户名称" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12">
<el-form-item label="所属行业" prop="industryId">
<el-select v-model="formData.industryId" placeholder="请选择所属行业">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_INDUSTRY)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="客户来源" prop="source"> <el-form-item label="客户来源" prop="source">
<el-select v-model="formData.source" placeholder="请选择客户来源"> <el-select v-model="formData.source" placeholder="请选择客户来源" class="w-1/1">
<el-option <el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_SOURCE)" v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_SOURCE)"
:key="dict.value" :key="dict.value"
@ -39,18 +25,6 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12">
<el-form-item label="客户级别" prop="level">
<el-select v-model="formData.level" placeholder="请选择客户级别">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_LEVEL)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
@ -59,20 +33,31 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="电话" prop="telephone"> <el-form-item label="负责人" prop="ownerUserId">
<el-input v-model="formData.telephone" placeholder="请输入电话" /> <el-select
v-model="formData.ownerUserId"
:disabled="formType !== 'create'"
class="w-1/1"
>
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="邮箱" prop="email"> <el-form-item label="电话" prop="telephone">
<el-input v-model="formData.email" placeholder="请输入邮箱" /> <el-input v-model="formData.telephone" placeholder="请输入电话" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="QQ" prop="qq"> <el-form-item label="邮箱" prop="email">
<el-input v-model="formData.qq" placeholder="请输入QQ" /> <el-input v-model="formData.email" placeholder="请输入邮箱" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -83,19 +68,46 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="网址" prop="website"> <el-form-item label="QQ" prop="qq">
<el-input v-model="formData.website" placeholder="请输入网址" /> <el-input v-model="formData.qq" placeholder="请输入 QQ" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="所在地" prop="areaId"> <el-form-item label="客户行业" prop="industryId">
<el-select v-model="formData.industryId" placeholder="请选择客户行业" class="w-1/1">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_INDUSTRY)"
: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="level">
<el-select v-model="formData.level" placeholder="请选择客户级别" class="w-1/1">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_LEVEL)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="地址" prop="areaId">
<el-tree-select <el-tree-select
v-model="formData.areaId" v-model="formData.areaId"
:data="areaList" :data="areaList"
:props="defaultProps" :props="defaultProps"
:render-after-expand="true" :render-after-expand="true"
class="w-1/1"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -105,16 +117,7 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-form-item v-if="formType === 'create'" label="负责人" prop="userIds" span="24"> <!-- TODO 芋艿待整理 -->
<el-select v-model="formData.ownerUserId">
<el-option
v-for="item in userOptions"
:key="parseInt(item.id)"
:label="item.nickname"
:value="parseInt(item.id)"
/>
</el-select>
</el-form-item>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="下次联系时间" prop="contactNextTime"> <el-form-item label="下次联系时间" prop="contactNextTime">
@ -126,17 +129,12 @@
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input type="textarea" v-model="formData.remark" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row> </el-row>
<el-col :span="24">
<el-form-item label="客户描述" prop="description">
<el-input v-model="formData.description" placeholder="请输入客户描述" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-form> </el-form>
<template #footer> <template #footer>
<el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button> <el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button>
@ -150,7 +148,7 @@ import * as CustomerApi from '@/api/crm/customer'
import * as AreaApi from '@/api/system/area' import * as AreaApi from '@/api/system/area'
import { defaultProps } from '@/utils/tree' import { defaultProps } from '@/utils/tree'
import * as UserApi from '@/api/system/user' import * as UserApi from '@/api/system/user'
import { CACHE_KEY, useCache } from '@/hooks/web/useCache' import { useUserStore } from '@/store/modules/user'
const { t } = useI18n() // const { t } = useI18n() //
const message = useMessage() // const message = useMessage() //
@ -164,21 +162,19 @@ const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
const formData = ref({ const formData = ref({
id: undefined, id: undefined,
name: undefined, name: undefined,
contactNextTime: undefined,
ownerUserId: 0,
mobile: undefined, mobile: undefined,
industryId: undefined,
level: undefined,
source: undefined,
telephone: undefined, telephone: undefined,
website: undefined,
qq: undefined, qq: undefined,
wechat: undefined, wechat: undefined,
email: undefined, email: undefined,
description: undefined,
remark: undefined,
areaId: undefined, areaId: undefined,
detailAddress: undefined, detailAddress: undefined,
contactNextTime: undefined, industryId: undefined,
ownerUserId: undefined level: undefined,
source: undefined,
remark: undefined
}) })
const formRules = reactive({ const formRules = reactive({
name: [{ required: true, message: '客户名称不能为空', trigger: 'blur' }], name: [{ required: true, message: '客户名称不能为空', trigger: 'blur' }],
@ -207,9 +203,7 @@ const open = async (type: string, id?: number) => {
userOptions.value = await UserApi.getSimpleUserList() userOptions.value = await UserApi.getSimpleUserList()
// //
if (formType.value === 'create') { if (formType.value === 'create') {
const { wsCache } = useCache() formData.value.ownerUserId = useUserStore().getUser.id
const user = wsCache.get(CACHE_KEY.USER).user
formData.value.ownerUserId = user.id
} }
} }
defineExpose({ open }) // open defineExpose({ open }) // open
@ -245,21 +239,19 @@ const resetForm = () => {
formData.value = { formData.value = {
id: undefined, id: undefined,
name: undefined, name: undefined,
contactNextTime: undefined,
ownerUserId: 0,
mobile: undefined, mobile: undefined,
industryId: undefined,
level: undefined,
source: undefined,
telephone: undefined, telephone: undefined,
website: undefined,
qq: undefined, qq: undefined,
wechat: undefined, wechat: undefined,
email: undefined, email: undefined,
description: undefined,
remark: undefined,
areaId: undefined, areaId: undefined,
detailAddress: undefined, detailAddress: undefined,
contactNextTime: undefined, industryId: undefined,
ownerUserId: undefined level: undefined,
source: undefined,
remark: undefined
} }
formRef.value?.resetFields() formRef.value?.resetFields()
} }

View File

@ -104,13 +104,12 @@
<!-- 列表 --> <!-- 列表 -->
<ContentWrap> <ContentWrap>
<el-tabs v-model="activeName" @tab-click="handleClick"> <el-tabs v-model="activeName" @tab-click="handleTabClick">
<el-tab-pane label="我负责的" name="1" /> <el-tab-pane label="我负责的" name="1" />
<el-tab-pane label="我参与的" name="2" /> <el-tab-pane label="我参与的" name="2" />
<el-tab-pane label="下属负责的" name="3" /> <el-tab-pane label="下属负责的" name="3" />
</el-tabs> </el-tabs>
<el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true">
<el-table-column align="center" label="编号" fixed="left" prop="id" />
<el-table-column align="center" label="客户名称" fixed="left" prop="name" width="160"> <el-table-column align="center" label="客户名称" fixed="left" prop="name" width="160">
<template #default="scope"> <template #default="scope">
<el-link :underline="false" type="primary" @click="openDetail(scope.row.id)"> <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)">
@ -118,24 +117,24 @@
</el-link> </el-link>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column align="center" label="手机" prop="mobile" width="120" />
<el-table-column align="center" label="电话" prop="telephone" width="120" />
<el-table-column align="center" label="客户来源" prop="source" width="100"> <el-table-column align="center" label="客户来源" prop="source" width="100">
<template #default="scope"> <template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" /> <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column align="center" label="所属行业" prop="industryId" width="120"> <el-table-column label="手机" align="center" prop="mobile" width="120" />
<template #default="scope"> <el-table-column label="电话" align="center" prop="telephone" width="130" />
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" /> <el-table-column label="邮箱" align="center" prop="email" width="180" />
</template> <el-table-column align="center" label="客户级别" prop="level" width="135">
</el-table-column>
<el-table-column align="center" label="客户级别" prop="level" width="130">
<template #default="scope"> <template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="scope.row.level" /> <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="scope.row.level" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column align="center" label="网址" prop="website" width="200" /> <el-table-column align="center" label="客户行业" prop="industryId" width="100">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" />
</template>
</el-table-column>
<el-table-column <el-table-column
:formatter="dateFormatter" :formatter="dateFormatter"
align="center" align="center"
@ -144,14 +143,16 @@
width="180px" width="180px"
/> />
<el-table-column align="center" label="备注" prop="remark" width="200" /> <el-table-column align="center" label="备注" prop="remark" width="200" />
<el-table-column align="center" label="锁定状态" prop="lockStatus">
<template #default="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.lockStatus" />
</template>
</el-table-column>
<el-table-column align="center" label="成交状态" prop="dealStatus"> <el-table-column align="center" label="成交状态" prop="dealStatus">
<template #default="scope"> <template #default="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.dealStatus" /> <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.dealStatus" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column align="center" label="距离进入公海" prop="poolDay" width="120">
<template #default="scope"> {{ scope.row.poolDay }} </template>
</el-table-column>
<el-table-column <el-table-column
:formatter="dateFormatter" :formatter="dateFormatter"
align="center" align="center"
@ -159,10 +160,17 @@
prop="contactLastTime" prop="contactLastTime"
width="180px" width="180px"
/> />
<el-table-column align="center" label="最后跟进记录" prop="contactLastContent" width="200" />
<el-table-column label="地址" align="center" prop="detailAddress" width="180" />
<el-table-column align="center" label="距离进入公海天数" prop="poolDay" width="140">
<template #default="scope"> {{ scope.row.poolDay }} </template>
</el-table-column>
<el-table-column align="center" label="负责人" prop="ownerUserName" width="100px" />
<el-table-column align="center" label="所属部门" prop="ownerUserDeptName" width="100px" />
<el-table-column <el-table-column
:formatter="dateFormatter" :formatter="dateFormatter"
align="center" align="center"
label="创建时间" label="更新时间"
prop="updateTime" prop="updateTime"
width="180px" width="180px"
/> />
@ -173,8 +181,6 @@
prop="createTime" prop="createTime"
width="180px" width="180px"
/> />
<el-table-column align="center" label="负责人" prop="ownerUserName" width="100px" />
<el-table-column align="center" label="所属部门" prop="ownerUserDeptName" width="100px" />
<el-table-column align="center" label="创建人" prop="creatorName" width="100px" /> <el-table-column align="center" label="创建人" prop="creatorName" width="100px" />
<el-table-column align="center" fixed="right" label="操作" min-width="150"> <el-table-column align="center" fixed="right" label="操作" min-width="150">
<template #default="scope"> <template #default="scope">
@ -228,62 +234,32 @@ const { t } = useI18n() // 国际化
const loading = ref(true) // const loading = ref(true) //
const total = ref(0) // const total = ref(0) //
const list = ref([]) // const list = ref([]) //
const queryParams = ref<{ const queryParams = reactive({
pageNo: number
pageSize: number
name: string
mobile: string
industryId: number | undefined
level: number | undefined
source: number | undefined
sceneType: number | undefined
pool: boolean | undefined
}>({
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
sceneType: '1', // activeName
name: '', name: '',
mobile: '', mobile: '',
industryId: undefined, industryId: undefined,
level: undefined, level: undefined,
source: undefined, source: undefined,
sceneType: undefined,
pool: undefined pool: undefined
}) })
const queryFormRef = ref() // const queryFormRef = ref() //
const exportLoading = ref(false) // const exportLoading = ref(false) //
const activeName = ref('1') // tab const activeName = ref('1') // tab
enum CrmSceneTypeEnum { /** tab 切换 */
OWNER = 1, const handleTabClick = (tab: TabsPaneContext) => {
INVOLVED = 2, queryParams.sceneType = tab.paneName
SUBORDINATE = 3 handleQuery()
}
const handleClick = (tab: TabsPaneContext) => {
switch (tab.paneName) {
case '1':
resetQuery(() => {
queryParams.value.sceneType = CrmSceneTypeEnum.OWNER
})
break
case '2':
resetQuery(() => {
queryParams.value.sceneType = CrmSceneTypeEnum.INVOLVED
})
break
case '3':
resetQuery(() => {
queryParams.value.sceneType = CrmSceneTypeEnum.SUBORDINATE
})
break
}
} }
/** 查询列表 */ /** 查询列表 */
const getList = async () => { const getList = async () => {
loading.value = true loading.value = true
try { try {
const data = await CustomerApi.getCustomerPage(queryParams.value) const data = await CustomerApi.getCustomerPage(queryParams)
list.value = data.list list.value = data.list
total.value = data.total total.value = data.total
} finally { } finally {
@ -293,25 +269,13 @@ const getList = async () => {
/** 搜索按钮操作 */ /** 搜索按钮操作 */
const handleQuery = () => { const handleQuery = () => {
queryParams.value.pageNo = 1 queryParams.pageNo = 1
getList() getList()
} }
/** 重置按钮操作 */ /** 重置按钮操作 */
const resetQuery = (func: Function | undefined = undefined) => { const resetQuery = () => {
queryFormRef.value.resetFields() queryFormRef.value.resetFields()
queryParams.value = {
pageNo: 1,
pageSize: 10,
name: '',
mobile: '',
industryId: undefined,
level: undefined,
source: undefined,
sceneType: undefined,
pool: undefined
}
func && func()
handleQuery() handleQuery()
} }
@ -353,7 +317,7 @@ const handleExport = async () => {
await message.exportConfirm() await message.exportConfirm()
// //
exportLoading.value = true exportLoading.value = true
const data = await CustomerApi.exportCustomer(queryParams.value) const data = await CustomerApi.exportCustomer(queryParams)
download.excel(data, '客户.xls') download.excel(data, '客户.xls')
} catch { } catch {
} finally { } finally {