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

View File

@ -29,7 +29,7 @@
<!-- 列表 -->
<ContentWrap>
<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">
<el-link :underline="false" type="primary" @click="openDetail(scope.row.id)">
{{ scope.row.name }}
@ -41,7 +41,7 @@
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" />
</template>
</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="email" 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-tabs>
<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">
<el-link :underline="false" type="primary" @click="openDetail(scope.row.id)">
{{ scope.row.name }}
@ -80,7 +80,7 @@
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" />
</template>
</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="email" 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-form-item>
</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-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
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_SOURCE)"
:key="dict.value"
@ -39,18 +25,6 @@
</el-select>
</el-form-item>
</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-col :span="12">
@ -59,20 +33,31 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="电话" prop="telephone">
<el-input v-model="formData.telephone" placeholder="请输入电话" />
<el-form-item label="负责人" prop="ownerUserId">
<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-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input v-model="formData.email" placeholder="请输入邮箱" />
<el-form-item label="电话" prop="telephone">
<el-input v-model="formData.telephone" 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" />
<el-form-item label="邮箱" prop="email">
<el-input v-model="formData.email" placeholder="请输入邮箱" />
</el-form-item>
</el-col>
</el-row>
@ -83,19 +68,46 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="网址" prop="website">
<el-input v-model="formData.website" placeholder="请输入网址" />
<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-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
v-model="formData.areaId"
:data="areaList"
:props="defaultProps"
:render-after-expand="true"
class="w-1/1"
/>
</el-form-item>
</el-col>
@ -105,16 +117,7 @@
</el-form-item>
</el-col>
</el-row>
<el-form-item v-if="formType === 'create'" label="负责人" prop="userIds" span="24">
<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>
<!-- TODO 芋艿待整理 -->
<el-row>
<el-col :span="12">
<el-form-item label="下次联系时间" prop="contactNextTime">
@ -126,17 +129,12 @@
/>
</el-form-item>
</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-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>
<template #footer>
<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 { defaultProps } from '@/utils/tree'
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 message = useMessage() //
@ -164,21 +162,19 @@ const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
const formData = ref({
id: undefined,
name: undefined,
contactNextTime: undefined,
ownerUserId: 0,
mobile: undefined,
industryId: undefined,
level: undefined,
source: undefined,
telephone: undefined,
website: undefined,
qq: undefined,
wechat: undefined,
email: undefined,
description: undefined,
remark: undefined,
areaId: undefined,
detailAddress: undefined,
contactNextTime: undefined,
ownerUserId: undefined
industryId: undefined,
level: undefined,
source: undefined,
remark: undefined
})
const formRules = reactive({
name: [{ required: true, message: '客户名称不能为空', trigger: 'blur' }],
@ -207,9 +203,7 @@ const open = async (type: string, id?: number) => {
userOptions.value = await UserApi.getSimpleUserList()
//
if (formType.value === 'create') {
const { wsCache } = useCache()
const user = wsCache.get(CACHE_KEY.USER).user
formData.value.ownerUserId = user.id
formData.value.ownerUserId = useUserStore().getUser.id
}
}
defineExpose({ open }) // open
@ -245,21 +239,19 @@ const resetForm = () => {
formData.value = {
id: undefined,
name: undefined,
contactNextTime: undefined,
ownerUserId: 0,
mobile: undefined,
industryId: undefined,
level: undefined,
source: undefined,
telephone: undefined,
website: undefined,
qq: undefined,
wechat: undefined,
email: undefined,
description: undefined,
remark: undefined,
areaId: undefined,
detailAddress: undefined,
contactNextTime: undefined,
ownerUserId: undefined
industryId: undefined,
level: undefined,
source: undefined,
remark: undefined
}
formRef.value?.resetFields()
}

View File

@ -104,13 +104,12 @@
<!-- 列表 -->
<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="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" label="编号" fixed="left" prop="id" />
<el-table-column align="center" label="客户名称" fixed="left" prop="name" width="160">
<template #default="scope">
<el-link :underline="false" type="primary" @click="openDetail(scope.row.id)">
@ -118,24 +117,24 @@
</el-link>
</template>
</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">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" />
</template>
</el-table-column>
<el-table-column align="center" label="所属行业" prop="industryId" width="120">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" />
</template>
</el-table-column>
<el-table-column align="center" label="客户级别" prop="level" width="130">
<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="email" width="180" />
<el-table-column align="center" label="客户级别" prop="level" width="135">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="scope.row.level" />
</template>
</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
:formatter="dateFormatter"
align="center"
@ -144,14 +143,16 @@
width="180px"
/>
<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">
<template #default="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.dealStatus" />
</template>
</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
:formatter="dateFormatter"
align="center"
@ -159,10 +160,17 @@
prop="contactLastTime"
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
:formatter="dateFormatter"
align="center"
label="创建时间"
label="更新时间"
prop="updateTime"
width="180px"
/>
@ -173,8 +181,6 @@
prop="createTime"
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" fixed="right" label="操作" min-width="150">
<template #default="scope">
@ -228,62 +234,32 @@ const { t } = useI18n() // 国际化
const loading = ref(true) //
const total = ref(0) //
const list = ref([]) //
const queryParams = ref<{
pageNo: number
pageSize: number
name: string
mobile: string
industryId: number | undefined
level: number | undefined
source: number | undefined
sceneType: number | undefined
pool: boolean | undefined
}>({
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
sceneType: '1', // activeName
name: '',
mobile: '',
industryId: undefined,
level: undefined,
source: undefined,
sceneType: undefined,
pool: undefined
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const activeName = ref('1') // tab
enum CrmSceneTypeEnum {
OWNER = 1,
INVOLVED = 2,
SUBORDINATE = 3
}
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
}
/** tab 切换 */
const handleTabClick = (tab: TabsPaneContext) => {
queryParams.sceneType = tab.paneName
handleQuery()
}
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await CustomerApi.getCustomerPage(queryParams.value)
const data = await CustomerApi.getCustomerPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
@ -293,25 +269,13 @@ const getList = async () => {
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNo = 1
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = (func: Function | undefined = undefined) => {
const resetQuery = () => {
queryFormRef.value.resetFields()
queryParams.value = {
pageNo: 1,
pageSize: 10,
name: '',
mobile: '',
industryId: undefined,
level: undefined,
source: undefined,
sceneType: undefined,
pool: undefined
}
func && func()
handleQuery()
}
@ -353,7 +317,7 @@ const handleExport = async () => {
await message.exportConfirm()
//
exportLoading.value = true
const data = await CustomerApi.exportCustomer(queryParams.value)
const data = await CustomerApi.exportCustomer(queryParams)
download.excel(data, '客户.xls')
} catch {
} finally {