客户详情页处理完成
This commit is contained in:
parent
2cc4715ae0
commit
f06f1f29c9
|
|
@ -22,9 +22,9 @@ export interface CustomerInforVO {
|
|||
ownerUserId: number // 负责人ID
|
||||
ownerTime: Date // 成为负责人时间
|
||||
depId: number // 部门ID
|
||||
contactLastTime: Date // 最后跟进时间
|
||||
contactLastContent: string // 最后跟进内容
|
||||
contactNextTime: Date // 下次联系时间
|
||||
latestFollowTime: Date // 最后跟进时间
|
||||
latestFollowContent: string // 最后跟进内容
|
||||
nextFollowTime: Date // 下次联系时间
|
||||
lockStatus: number // 锁定状态(0:未锁,1:锁定)
|
||||
openSeaId: number // 公海ID
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,33 +9,15 @@ export interface CustomerLabelsVO {
|
|||
|
||||
// 客户标签 API
|
||||
export const CustomerLabelsApi = {
|
||||
// 查询客户标签分页
|
||||
getCustomerLabelsPage: async (params: any) => {
|
||||
return await request.get({ url: `/crm/customer-labels/page`, params })
|
||||
},
|
||||
|
||||
// 查询客户标签详情
|
||||
getCustomerLabels: async (id: number) => {
|
||||
return await request.get({ url: `/crm/customer-labels/get?id=` + id })
|
||||
},
|
||||
getCustomerLabelsList: async (params: any) => {
|
||||
return await request.get({ url: `/crm/customer-labels/list`, params })
|
||||
},
|
||||
|
||||
// 新增客户标签
|
||||
createCustomerLabels: async (data: CustomerLabelsVO) => {
|
||||
return await request.post({ url: `/crm/customer-labels/create`, data })
|
||||
createCustomerLabels: async (params: any) => {
|
||||
return await request.post({ url: `/crm/customer-labels/create`, params })
|
||||
},
|
||||
|
||||
// 修改客户标签
|
||||
updateCustomerLabels: async (data: CustomerLabelsVO) => {
|
||||
return await request.put({ url: `/crm/customer-labels/update`, data })
|
||||
},
|
||||
|
||||
// 删除客户标签
|
||||
deleteCustomerLabels: async (id: number) => {
|
||||
return await request.delete({ url: `/crm/customer-labels/delete?id=` + id })
|
||||
},
|
||||
|
||||
// 导出客户标签 Excel
|
||||
exportCustomerLabels: async (params) => {
|
||||
return await request.download({ url: `/crm/customer-labels/export-excel`, params })
|
||||
}
|
||||
}
|
||||
|
|
@ -5,9 +5,7 @@ export interface FollwRecordVO {
|
|||
id: number // 唯一标识
|
||||
customerId: number // 客户ID
|
||||
content: string // 跟进内容
|
||||
createTime: string // 创建时间
|
||||
creator: string // 创建人
|
||||
userId: string // 客户经理
|
||||
userId: number // 客户经理
|
||||
}
|
||||
|
||||
// 跟进记录 API
|
||||
|
|
@ -17,6 +15,11 @@ export const FollwRecordApi = {
|
|||
return await request.get({ url: `/crm/follw-record/page`, params })
|
||||
},
|
||||
|
||||
// 新增跟进记录
|
||||
createFollwRecord: async (data: FollwRecordVO) => {
|
||||
return await request.post({ url: `/crm/follw-record/create`, data })
|
||||
},
|
||||
|
||||
// 查询跟进记录详情
|
||||
getFollwRecord: async (id: number) => {
|
||||
return await request.get({ url: `/crm/follw-record/get?id=` + id })
|
||||
|
|
|
|||
|
|
@ -3,13 +3,32 @@
|
|||
<!-- 顶部标题和操作按钮区域 -->
|
||||
<div class="flex justify-between mb-2">
|
||||
<div class="flex items-center">
|
||||
<h2 class="text-xl font-bold mr-10px min-w-[100px]" >{{ customerForm.customerName }}({{ customerForm.mobile }})</h2>
|
||||
<h2 >{{ customerForm.customerName }}({{ customerForm.mobile }})</h2>
|
||||
<span class="ml-2px text-sm">撞库次数: {{ customerForm.repeatCount }}次</span>
|
||||
<span class="text-sm ml-2">跟进次数: {{ customerForm.followCount }}次</span>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<el-button size="small" class="mr-1" :disabled="!props.prevId" @click="emit('prev')">上一条</el-button>
|
||||
<el-button size="small" :disabled="!props.nextId" @click="emit('next')">下一条</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
class="mr-2"
|
||||
type="primary"
|
||||
plain
|
||||
:disabled="!props.prevId"
|
||||
@click="emit('prev')"
|
||||
>
|
||||
<Icon icon="ep:arrow-left" class="mr-1" />
|
||||
上一条
|
||||
</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
plain
|
||||
:disabled="!props.nextId"
|
||||
@click="emit('next')"
|
||||
>
|
||||
下一条
|
||||
<Icon icon="ep:arrow-right" class="ml-1" />
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 操作按钮栏 -->
|
||||
|
|
@ -50,16 +69,16 @@
|
|||
<div class="rightContent w-[calc(100%-300px)]">
|
||||
<el-tabs>
|
||||
<el-tab-pane label="客户资料">
|
||||
<div class="mt-4">
|
||||
<QuickFollow />
|
||||
<Infor />
|
||||
<div class="mt-4">
|
||||
<QuickFollow :customer-id="props.customerId" :customer-form="customerForm" />
|
||||
<Infor :customer-id="props.customerId" :customer-form="customerForm" />
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</ContentWrap>
|
||||
</ContentWrap>
|
||||
<!-- 分配弹窗 -->
|
||||
<AllocateForm ref="formRef" />
|
||||
<!-- 转公海弹窗 -->
|
||||
|
|
@ -92,25 +111,9 @@ const transferFormRef = ref() // 转公海表单的 Ref
|
|||
// 客户表单数据
|
||||
const customerForm = ref({
|
||||
id: undefined as number | undefined,
|
||||
sex: 1,
|
||||
age: undefined as string | undefined,
|
||||
customerName: '',
|
||||
expectAmount: undefined as string | undefined,
|
||||
city: '',
|
||||
customerLevel: 0,
|
||||
customerType: '潜在',
|
||||
followContent: '',
|
||||
mobile: '',
|
||||
remark: '',
|
||||
customerSourceId: undefined,
|
||||
customerTypeId: undefined,
|
||||
importLevelId: undefined,
|
||||
followStatusId: undefined,
|
||||
ownerUserId: undefined,
|
||||
depId: undefined,
|
||||
contactLastTime: undefined,
|
||||
contactLastContent: undefined,
|
||||
createTime: undefined,
|
||||
repeatCount: 0,
|
||||
followCount: 0
|
||||
})
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<div v-if="loading" class="text-center py-4">加载中...</div>
|
||||
<div v-if="finished" class="text-center text-gray-400 py-4">没有更多了</div>
|
||||
</el-timeline>
|
||||
<div v-else class="text-center text-gray-400 py-4">暂无跟进记录</div>
|
||||
<div v-else class="text-center text-gray-400 py-4">暂无记录</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@
|
|||
<div class="w-1 h-3.5 bg-blue-500 rounded-full mr-2"></div>
|
||||
基本信息
|
||||
</div>
|
||||
<el-button type="primary" size="small" class="text-xs !px-3 !py-1.5">保存</el-button>
|
||||
<el-button type="primary" size="small" class="text-xs !px-3 !py-1.5" @click="handleSave">保存</el-button>
|
||||
</div>
|
||||
|
||||
<el-form :model="form" label-width="80px" class="bg-white p-4 rounded-lg text-xs">
|
||||
<el-form :model="form" label-width="80px" class="bg-white p-4 rounded-lg text-xs">
|
||||
|
||||
<!-- 选择器组 -->
|
||||
<div class="flex items-center gap-6 mb-3 pb-2 border-b border-gray-100">
|
||||
|
|
@ -25,21 +25,24 @@
|
|||
placeholder="请输入"
|
||||
class="!w-[120px]"
|
||||
size="small"
|
||||
type="number"
|
||||
min="0"
|
||||
max="150"
|
||||
@input="(val) => form.age = val ? Number(val) : 0"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form-item>
|
||||
<el-form-item label-class="text-gray-600 text-xs" label="性别" prop="sex" class="!mb-0 !text-xs" >
|
||||
<el-select
|
||||
v-model="form.sex"
|
||||
placeholder="请选择"
|
||||
class="!w-[120px]"
|
||||
size="small"
|
||||
>
|
||||
<el-option label="未知" value="0" class="!text-xs" />
|
||||
<el-option label="男" value="1" class="!text-xs" />
|
||||
<el-option label="女" value="2" class="!text-xs" />
|
||||
</el-select>
|
||||
<el-select v-model="form.sex" placeholder="请选择" class="!w-120px">
|
||||
<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>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="flex items-center gap-6 mb-3 pb-2 border-b border-gray-100">
|
||||
|
||||
|
|
@ -51,9 +54,9 @@
|
|||
size="small"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label-class="text-gray-600 text-xs" label="居住地址" prop="adress" class="!mb-0 !text-xs" >
|
||||
<el-form-item label-class="text-gray-600 text-xs" label="居住地址" prop="address" class="!mb-0 !text-xs" >
|
||||
<el-input
|
||||
v-model="form.adress"
|
||||
v-model="form.address"
|
||||
placeholder="请输入"
|
||||
class="!w-[350px]"
|
||||
size="small"
|
||||
|
|
@ -61,8 +64,6 @@
|
|||
</el-form-item>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- 备注 -->
|
||||
<div class="flex items-start">
|
||||
<el-form-item label-class="text-gray-600 text-xs" label="客户信息" class="flex-1 !text-xs">
|
||||
|
|
@ -83,65 +84,75 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, onMounted } from 'vue'
|
||||
import { useCrmStore } from '@/store/modules/crm'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { buildTree } from '@/utils/tree'
|
||||
import {CustomerInforApi,CustomerInforVO}from '@/api/crm/customer/customer'
|
||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
import { useMessage } from '@/hooks/web/useMessage'
|
||||
|
||||
const props = defineProps<{
|
||||
customerId?: number
|
||||
customerForm?: {
|
||||
id?: number
|
||||
customerName: string
|
||||
followContent: string
|
||||
mobile: string
|
||||
repeatCount: number
|
||||
followCount: number
|
||||
}
|
||||
}>()
|
||||
|
||||
// 从 CRM store 中获取数据
|
||||
const crmStore = useCrmStore()
|
||||
const { importLevelList, customerTypeList, customerLabelList, followLabelList } = storeToRefs(crmStore)
|
||||
const customerTypeOptions = ref<any>()
|
||||
|
||||
// cascader 配置
|
||||
const cascaderProps = {
|
||||
emitPath: false
|
||||
}
|
||||
const message = useMessage()
|
||||
|
||||
const form = ref({
|
||||
sex: 1,
|
||||
age: undefined as string | undefined,
|
||||
id: 0,
|
||||
age: 0,
|
||||
sex: 0,
|
||||
customerName: '',
|
||||
expectAmount: undefined as string | undefined,
|
||||
adress: '',
|
||||
remark: '',
|
||||
expectAmount: undefined,
|
||||
address: '',
|
||||
remark: ''
|
||||
})
|
||||
|
||||
// 监听 customerId 变化
|
||||
watch(() => props.customerId, async (id) => {
|
||||
watch([() => props.customerId, () => props.customerForm], async ([id, customerForm]) => {
|
||||
if (id) {
|
||||
try {
|
||||
// 这里添加获取客户跟进信息的API调用
|
||||
// const data = await CustomerApi.getCustomerFollowInfo(id)
|
||||
// Object.assign(form.value, data)
|
||||
const data = await CustomerInforApi.getCustomer(id)
|
||||
Object.assign(form.value, data)
|
||||
// If customerForm is provided, update relevant fields
|
||||
if (customerForm) {
|
||||
form.value = {
|
||||
...form.value,
|
||||
customerName: customerForm.customerName,
|
||||
id: customerForm.id || form.value.id,
|
||||
// Keep other fields from the API response
|
||||
age: form.value.age,
|
||||
sex: form.value.sex,
|
||||
expectAmount: form.value.expectAmount,
|
||||
address: form.value.address,
|
||||
remark: form.value.remark
|
||||
}
|
||||
}
|
||||
console.log(form.value)
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch customer follow info:', error)
|
||||
message.error('获取客户信息失败')
|
||||
}
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
// 初始化数据
|
||||
// 初始化数据
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await Promise.all([
|
||||
crmStore.getImportLevelList(),
|
||||
crmStore.getCustomerTypeList(),
|
||||
crmStore.getCustomerLabelList(),
|
||||
crmStore.getFollowLabelList()
|
||||
])
|
||||
// 构建客户类型树形结构
|
||||
customerTypeOptions.value = buildTree(customerTypeList.value)
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize data:', error)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
// 保存
|
||||
const handleSave = () => {
|
||||
// TODO: 实现保存逻辑
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
const data = form.value as unknown as CustomerInforVO
|
||||
await CustomerInforApi.updateCustomer(data)
|
||||
message.success('保存成功')
|
||||
} catch (error) {
|
||||
message.error('保存失败')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,219 +1,369 @@
|
|||
<template>
|
||||
<div class="flex justify-between items-center mb-2 bg-gray-50 px-4 py-2 rounded-md border border-gray-100">
|
||||
<div class="text-xs font-medium text-gray-700 flex items-center">
|
||||
<div class="w-1 h-3.5 bg-blue-500 rounded-full mr-2"></div>
|
||||
快捷输入
|
||||
<div>
|
||||
|
||||
|
||||
<div class="flex justify-between items-center mb-2 bg-gray-50 px-4 py-2 rounded-md border border-gray-100">
|
||||
<div class="text-xs font-medium text-gray-700 flex items-center">
|
||||
<div class="w-1 h-3.5 bg-blue-500 rounded-full mr-2"></div>
|
||||
快捷输入
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<el-button type="primary" size="small" class="text-xs !px-3 !py-1.5" @click="handleSave">保存</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-button type="primary" size="small" class="text-xs !px-3 !py-1.5">保存</el-button>
|
||||
</div>
|
||||
|
||||
<el-form :model="form" label-width="80px" class="bg-white p-4 rounded-lg text-xs">
|
||||
<!-- 开关选项组 -->
|
||||
<div class="flex items-center gap-4 mb-3 pb-2 border-b border-gray-100">
|
||||
<el-form-item label="车" class="!mb-0 !text-xs">
|
||||
<el-switch v-model="form.haveCar" size="small" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px" class="bg-white p-4 rounded-lg text-xs">
|
||||
<!-- 开关选项组 -->
|
||||
<div class="flex items-center gap-4 mb-3 pb-2 border-b border-gray-100">
|
||||
<el-form-item label="车" class="!mb-0 !text-xs">
|
||||
<el-switch
|
||||
v-model="form.haveCar"
|
||||
size="small"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="房" class="!mb-0 !text-xs">
|
||||
<el-switch v-model="form.haveHouse" size="small" />
|
||||
</el-form-item>
|
||||
<el-form-item label="房" class="!mb-0 !text-xs">
|
||||
<el-switch
|
||||
v-model="form.haveHouse"
|
||||
size="small"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="社保" class="!mb-0 !text-xs">
|
||||
<el-switch v-model="form.haveSocialSecurity" size="small" />
|
||||
</el-form-item>
|
||||
<el-form-item label="社保" class="!mb-0 !text-xs">
|
||||
<el-switch
|
||||
v-model="form.haveSocialSecurity"
|
||||
size="small"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="公积" class="!mb-0 !text-xs">
|
||||
<el-switch v-model="form.haveProvidentFund" size="small" />
|
||||
</el-form-item>
|
||||
<el-form-item label="公积金" class="!mb-0 !text-xs">
|
||||
<el-switch
|
||||
v-model="form.haveProvidentFund"
|
||||
size="small"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="保单" class="!mb-0 !text-xs">
|
||||
<el-switch v-model="form.haveGuaranteeSlip" size="small" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item label="保单" class="!mb-0 !text-xs">
|
||||
<el-switch
|
||||
v-model="form.haveGuaranteeSlip"
|
||||
size="small"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 选择器组 -->
|
||||
<div class="flex items-center gap-6 mb-3 pb-2 border-b border-gray-100">
|
||||
<el-form-item label-class="text-gray-600 text-xs" label="客户类型" prop="customerTypeId" class="!mb-0 !text-xs">
|
||||
<el-cascader
|
||||
v-model="form.customerTypeId"
|
||||
:show-all-levels="false"
|
||||
:options="customerTypeOptions"
|
||||
:props="cascaderProps"
|
||||
clearable
|
||||
placeholder="请选择"
|
||||
class="!w-[150px]"
|
||||
size="small"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="重要程度" prop="importLevelId" class="!mb-0 !text-xs">
|
||||
<el-select
|
||||
v-model="form.importLevelId"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
class="!w-[150px]"
|
||||
size="small"
|
||||
>
|
||||
<el-option
|
||||
v-for="iml in importLevelList"
|
||||
:key="iml.id"
|
||||
:value="iml.id"
|
||||
:label="iml.name"
|
||||
class="!text-xs"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="重点客户" class="!mb-0 !text-xs">
|
||||
<el-switch v-model="form.haveGuaranteeSlip" size="small" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-6 mb-3 pb-2 border-b border-gray-100">
|
||||
<el-form-item label-class="text-gray-600 text-xs" label="下次跟进" prop="nextFollowTime" class="!mb-0 !text-xs">
|
||||
<div class="flex items-center gap-2">
|
||||
<el-date-picker
|
||||
v-model="form.nextFollowTime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
type="datetime"
|
||||
placeholder="请选择时间"
|
||||
<!-- 选择器组 -->
|
||||
<div class="flex items-center gap-6 mb-3 pb-2 border-b border-gray-100">
|
||||
<el-form-item label-class="text-gray-600 text-xs" label="客户类型" prop="customerTypeId" class="!mb-0 !text-xs">
|
||||
<el-cascader
|
||||
v-model="form.customerTypeId"
|
||||
:show-all-levels="false"
|
||||
:options="customerTypeOptions"
|
||||
:props="cascaderProps"
|
||||
clearable
|
||||
placeholder="请选择"
|
||||
class="!w-[150px]"
|
||||
size="small"
|
||||
/>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
class="!text-xs"
|
||||
plain
|
||||
@click="setNextFollowTime(15)"
|
||||
>15分钟</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
class="!text-xs"
|
||||
plain
|
||||
@click="setNextFollowTime(30)"
|
||||
>30分钟</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
class="!text-xs"
|
||||
plain
|
||||
@click="setNextFollowTime(60)"
|
||||
>1小时</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
class="!text-xs"
|
||||
plain
|
||||
@click="setNextFollowTime(1440)"
|
||||
>1天后</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
class="!text-xs"
|
||||
plain
|
||||
@click="setNextFollowTime(4320)"
|
||||
>3天后</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="重要程度" prop="importLevelId" class="!mb-0 !text-xs">
|
||||
<el-select
|
||||
v-model="form.importLevelId"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
class="!w-[150px]"
|
||||
size="small"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in importLevelList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
class="!text-xs"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="重点客户" class="!mb-0 !text-xs">
|
||||
<el-switch v-model="form.isImport" size="small" :active-value="1" :inactive-value="0"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 标签组 -->
|
||||
<div class="mb-3 pb-2 border-b border-gray-100">
|
||||
<el-form-item label-class="text-gray-600 text-xs" label="客户标签" class="!mb-0 !text-xs">
|
||||
<div class="flex items-center gap-6 mb-3 pb-2 border-b border-gray-100">
|
||||
<el-form-item label-class="text-gray-600 text-xs" label="下次跟进" prop="nextFollowTime" class="!mb-0 !text-xs">
|
||||
<div class="flex items-center gap-2">
|
||||
<el-date-picker
|
||||
v-model="form.nextFollowTime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
type="datetime"
|
||||
placeholder="请选择时间"
|
||||
class="!w-[150px]"
|
||||
size="small"
|
||||
/>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
class="!text-xs"
|
||||
plain
|
||||
@click="setNextFollowTime(15)"
|
||||
>15分钟</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
class="!text-xs"
|
||||
plain
|
||||
@click="setNextFollowTime(30)"
|
||||
>30分钟</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
class="!text-xs"
|
||||
plain
|
||||
@click="setNextFollowTime(60)"
|
||||
>1小时</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
class="!text-xs"
|
||||
plain
|
||||
@click="setNextFollowTime(1440)"
|
||||
>1天后</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
class="!text-xs"
|
||||
plain
|
||||
@click="setNextFollowTime(4320)"
|
||||
>3天后</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 标签组 -->
|
||||
<div class="mb-3 pb-2 border-b border-gray-100">
|
||||
<el-form-item label-class="text-gray-600 text-xs" label="客户标签" class="!mb-0 !text-xs">
|
||||
<div class="flex flex-wrap gap-1.5">
|
||||
<el-check-tag
|
||||
v-for="label in customerLabelList"
|
||||
:key="label.id"
|
||||
:checked="customerLabels.includes(label.id)"
|
||||
@change="(checked) => handleCustomerLablesChange(label.id, checked)"
|
||||
class="!cursor-pointer hover:!border-primary !text-xs !py-0 !px-1.5"
|
||||
>
|
||||
{{ label.name }}
|
||||
</el-check-tag>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 备注 -->
|
||||
<div class="flex items-start">
|
||||
<el-form-item label-class="text-gray-600 text-xs" label="跟进备注" class="flex-1 !text-xs">
|
||||
<el-input
|
||||
v-model="content"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入跟进备注"
|
||||
resize="none"
|
||||
size="small"
|
||||
class="[&_.el-textarea__inner]:!text-xs"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<label class="text-gray-600 w-[80px] text-xs"></label>
|
||||
<div class="flex flex-wrap gap-1.5">
|
||||
<el-check-tag
|
||||
v-for="label in customerLabelList"
|
||||
v-for="label in followLabelList"
|
||||
:key="label.id"
|
||||
:modelValue="form.labelIds?.includes(label.id)"
|
||||
@change="(checked) => handleLabelChange(label.id, checked)"
|
||||
@click.stop="handleLabelClick(label)"
|
||||
class="!cursor-pointer hover:!border-primary !text-xs !py-0 !px-1.5"
|
||||
>
|
||||
{{ label.name }}
|
||||
{{ label.name }}
|
||||
</el-check-tag>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 备注 -->
|
||||
<div class="flex items-start">
|
||||
<el-form-item label-class="text-gray-600 text-xs" label="跟进备注" class="flex-1 !text-xs">
|
||||
<el-input
|
||||
v-model="form.content"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入跟进备注"
|
||||
resize="none"
|
||||
size="small"
|
||||
class="[&_.el-textarea__inner]:!text-xs"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<label class="text-gray-600 w-[80px] text-xs"></label>
|
||||
<div class="flex flex-wrap gap-1.5">
|
||||
<el-check-tag
|
||||
v-for="label in followLabelList"
|
||||
:key="label.id"
|
||||
:modelValue="form.labelIds?.includes(label.id)"
|
||||
@change="(checked) => handleLabelChange(label.id, checked)"
|
||||
class="!cursor-pointer hover:!border-primary !text-xs !py-0 !px-1.5"
|
||||
>
|
||||
{{ label.name }}
|
||||
</el-check-tag>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, onMounted } from 'vue'
|
||||
import { useCrmStore } from '@/store/modules/crm'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { buildTree } from '@/utils/tree'
|
||||
import dayjs from 'dayjs'
|
||||
import { CustomerInforApi, type CustomerInforVO } from '@/api/crm/customer/customer'
|
||||
import { CustomerLabelsApi } from '@/api/crm/customer/labels'
|
||||
import { useMessage } from '@/hooks/web/useMessage'
|
||||
import { FollwRecordApi, FollwRecordVO } from '@/api/crm/follw'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import request from '@/config/axios'
|
||||
|
||||
const props = defineProps<{
|
||||
customerId?: number
|
||||
const props = defineProps<{
|
||||
customerId?: number,
|
||||
prevId?: number,
|
||||
nextId?: number,
|
||||
customerForm: any
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['prev', 'next'])
|
||||
|
||||
const message = useMessage()
|
||||
|
||||
// 从 CRM store 中获取数据
|
||||
const crmStore = useCrmStore()
|
||||
const { importLevelList, customerTypeList, customerLabelList, followLabelList } = storeToRefs(crmStore)
|
||||
const customerTypeOptions = ref<any>()
|
||||
const content = ref()
|
||||
const customerLabels = ref<number[]>([])
|
||||
const formRef = ref()
|
||||
|
||||
// cascader 配置
|
||||
const cascaderProps = {
|
||||
emitPath: false
|
||||
}
|
||||
|
||||
const form = ref({
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 表单数据
|
||||
const form = ref<{
|
||||
id: number,
|
||||
haveCar: number | undefined
|
||||
haveHouse: number | undefined
|
||||
haveProvidentFund: number | undefined
|
||||
haveSocialSecurity: number | undefined
|
||||
haveGuaranteeSlip: number | undefined
|
||||
customerTypeId: number | undefined
|
||||
importLevelId: number | undefined
|
||||
isImport: number | undefined
|
||||
customerLabelIds: number[]
|
||||
nextFollowTime: string | undefined
|
||||
}>({
|
||||
id: 0,
|
||||
haveCar: undefined,
|
||||
haveHouse: undefined,
|
||||
haveProvidentFund: undefined,
|
||||
haveSocialSecurity: undefined,
|
||||
haveProvidentFund: undefined,
|
||||
haveSocialSecurity: undefined,
|
||||
haveGuaranteeSlip: undefined,
|
||||
customerTypeId: undefined,
|
||||
importLevelId: undefined,
|
||||
labelIds: [] as number[],
|
||||
content: undefined,
|
||||
nextFollowTime: undefined as string | undefined
|
||||
isImport: undefined,
|
||||
customerLabelIds: [],
|
||||
nextFollowTime: undefined
|
||||
})
|
||||
|
||||
// 表单验证规则
|
||||
const rules = {
|
||||
importLevelId: [{ required: true, message: '请选择重要程度', trigger: 'change' }]
|
||||
}
|
||||
|
||||
// 监听 customerId 变化
|
||||
watch(() => props.customerId, async (id) => {
|
||||
watch([() => props.customerId, () => props.customerForm], async ([id, customerForm]) => {
|
||||
if (id) {
|
||||
try {
|
||||
// 这里添加获取客户跟进信息的API调用
|
||||
// const data = await CustomerApi.getCustomerFollowInfo(id)
|
||||
// Object.assign(form.value, data)
|
||||
// 获取客户详情
|
||||
const data = await CustomerInforApi.getCustomer(id)
|
||||
// 更新表单数据
|
||||
Object.assign(form.value, data)
|
||||
// 如果 importLevelId 是 null 或 0,设置为 undefined
|
||||
form.value.importLevelId = data.importLevelId && data.importLevelId !== 0 ? data.importLevelId : undefined
|
||||
|
||||
// 重置标签和内容
|
||||
customerLabels.value = []
|
||||
content.value = ''
|
||||
|
||||
// 获取客户现有的标签
|
||||
const lbs = await CustomerLabelsApi.getCustomerLabelsList({ customerId: props.customerId })
|
||||
// 更新选中的标签
|
||||
customerLabels.value = lbs.map((label: any) => label.customerLabelId)
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch customer follow info:', error)
|
||||
message.error('获取客户信息失败')
|
||||
}
|
||||
} else {
|
||||
// 重置标签和内容
|
||||
customerLabels.value = []
|
||||
content.value = ''
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
// 处理标签点击
|
||||
const handleLabelClick = (label: any) => {
|
||||
content.value = content.value ? `${content.value} ${label.name}` : label.name
|
||||
}
|
||||
|
||||
// 处理客户标签变化
|
||||
const handleCustomerLablesChange = (labelId: number, checked: boolean) => {
|
||||
if (checked) {
|
||||
// 如果标签被选中,添加到数组中
|
||||
customerLabels.value.push(labelId)
|
||||
} else {
|
||||
// 如果标签被取消选中,从数组中移除
|
||||
customerLabels.value = customerLabels.value.filter(id => id !== labelId)
|
||||
}
|
||||
}
|
||||
|
||||
// 设置下次跟进时间
|
||||
const setNextFollowTime = (minutes: number) => {
|
||||
form.value.nextFollowTime = minutes ? dayjs().add(minutes, 'minute').format('YYYY-MM-DD HH:mm:ss') : undefined
|
||||
}
|
||||
|
||||
// 保存
|
||||
const handleSave = async () => {
|
||||
// 表单验证
|
||||
try {
|
||||
if (!form.value.importLevelId) {
|
||||
message.warning('请选择重要程度')
|
||||
formRef.value.validateField('importLevelId')
|
||||
return
|
||||
}
|
||||
|
||||
//1:修改客户基本信息
|
||||
const data = form.value as unknown as CustomerInforVO
|
||||
await CustomerInforApi.updateCustomer(data)
|
||||
|
||||
//2:添加跟进记录
|
||||
if (content.value) {
|
||||
const followRecord: FollwRecordVO = {
|
||||
id: 0,
|
||||
customerId: props.customerId!,
|
||||
content: content.value,
|
||||
userId: userStore.getUser.id
|
||||
}
|
||||
await FollwRecordApi.createFollwRecord(followRecord)
|
||||
}
|
||||
|
||||
//3:添加客户标签
|
||||
if (props.customerId && customerLabels.value.length > 0) {
|
||||
await request.post({
|
||||
url: '/crm/customer-labels/create',
|
||||
data: {
|
||||
customerId: props.customerId,
|
||||
customerLabelIds: customerLabels.value
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
message.success('保存成功')
|
||||
} catch (error: any) {
|
||||
// 只有在实际保存操作失败时才显示错误
|
||||
if (error?.message) {
|
||||
message.error(error.message)
|
||||
} else {
|
||||
message.error('保存失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化数据
|
||||
onMounted(async () => {
|
||||
try {
|
||||
|
|
@ -221,36 +371,14 @@ onMounted(async () => {
|
|||
crmStore.getImportLevelList(),
|
||||
crmStore.getCustomerTypeList(),
|
||||
crmStore.getCustomerLabelList(),
|
||||
crmStore.getFollowLabelList()
|
||||
crmStore.getFollowLabelList()
|
||||
])
|
||||
// 构建客户类型树形结构
|
||||
customerTypeOptions.value = buildTree(customerTypeList.value)
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize data:', error)
|
||||
message.error('初始化失败')
|
||||
}
|
||||
})
|
||||
|
||||
// 处理标签选择
|
||||
const handleLabelChange = (labelId: number, checked: boolean) => {
|
||||
if (checked) {
|
||||
form.value.labelIds.push(labelId)
|
||||
} else {
|
||||
const index = form.value.labelIds.indexOf(labelId)
|
||||
if (index !== -1) {
|
||||
form.value.labelIds.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置下次跟进时间
|
||||
const setNextFollowTime = (minutes: number) => {
|
||||
form.value.nextFollowTime = dayjs().add(minutes, 'minute').format('YYYY-MM-DD HH:mm:ss')
|
||||
}
|
||||
|
||||
// 保存
|
||||
const handleSave = () => {
|
||||
// TODO: 实现保存逻辑
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
|
|
@ -1,15 +1,8 @@
|
|||
<template>
|
||||
<div class="transfer-record-container">
|
||||
<el-timeline
|
||||
v-if="transferRecordList.length > 0"
|
||||
v-infinite-scroll="loadMore"
|
||||
:infinite-scroll-disabled="disabled"
|
||||
:infinite-scroll-immediate="false"
|
||||
:infinite-scroll-distance="50"
|
||||
class="timeline-wrapper"
|
||||
>
|
||||
<div class="mt-4">
|
||||
<el-timeline v-if="transferRecordList.length > 0" v-infinite-scroll="loadMore" :infinite-scroll-disabled="disabled">
|
||||
<el-timeline-item v-for="item in transferRecordList" :key="item.id">
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex items-center">
|
||||
<span class="text-gray-500 w-[80px]">数据位置:</span>
|
||||
<span>{{ getDictLabel(DICT_TYPE.CRM_CUSTOMER_DATA_BELONG, item.type) }}</span>
|
||||
|
|
@ -32,7 +25,7 @@
|
|||
<div v-if="loading" class="text-center py-4">加载中...</div>
|
||||
<div v-if="finished" class="text-center text-gray-400 py-4">没有更多了</div>
|
||||
</el-timeline>
|
||||
<div v-else class="text-center text-gray-400 py-4">暂无流转记录</div>
|
||||
<div v-else class="text-center text-gray-400 py-4">暂无记录</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -130,28 +123,9 @@ watch(() => props.customerId, async (id) => {
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
.transfer-record-container {
|
||||
height: calc(100vh - 240px);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.timeline-wrapper {
|
||||
height: 100%;
|
||||
.el-timeline {
|
||||
padding-right: 10px;
|
||||
max-height: calc(100vh - 240px);
|
||||
overflow-y: auto;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
.timeline-wrapper::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.timeline-wrapper::-webkit-scrollbar-thumb {
|
||||
background-color: #dcdfe6;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.timeline-wrapper::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -302,13 +302,7 @@
|
|||
|
||||
<!-- 客户详情抽屉 -->
|
||||
<el-drawer v-model="drawerVisible" size="80%" :destroy-on-close="true" :with-header="false" :show-close="true">
|
||||
<CustomerDetail
|
||||
:customer-id="customerId"
|
||||
:prev-id="prevId"
|
||||
:next-id="nextId"
|
||||
@prev="handlePrevNextClick('prev')"
|
||||
@next="handlePrevNextClick('next')"
|
||||
/>
|
||||
<CustomerDetail :customer-id="customerId" />
|
||||
</el-drawer>
|
||||
|
||||
<!-- 转公海弹窗 -->
|
||||
|
|
@ -320,7 +314,6 @@
|
|||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
import { buildTree } from '@/utils/tree'
|
||||
import { handlePrevNext } from '@/utils/crm'
|
||||
import { CustomerInforApi, CustomerInforVO } from '@/api/crm/customer/customer'
|
||||
import CustomerDetail from '@/views/crm/components/Customer/Detail.vue'
|
||||
import TransferForm from '@/views/crm/components/Transfer/TransferForm.vue'
|
||||
|
|
@ -370,8 +363,6 @@ let customerSourceOptions = ref<any>();
|
|||
let customerTypeOptions = ref<any>();
|
||||
const drawerVisible = ref(false) // 抽屉是否显示
|
||||
const customerId = ref<number>() // 当前查看的客户ID
|
||||
const prevId = ref<number>(0) // 上一条记录ID
|
||||
const nextId = ref<number>(0) // 下一条记录ID
|
||||
const cascaderProps= {
|
||||
emitPath: false,
|
||||
}
|
||||
|
|
@ -404,31 +395,9 @@ const resetQuery = () => {
|
|||
/** 打开跟进抽屉 */
|
||||
const openInforForm = (id?: number) => {
|
||||
customerId.value = id
|
||||
// 找到当前记录在列表中的索引
|
||||
const currentIndex = list.value.findIndex(item => item.id === id)
|
||||
|
||||
// 获取上一条和下一条记录的ID
|
||||
prevId.value = currentIndex > 0 ? list.value[currentIndex - 1].id : 0
|
||||
nextId.value = currentIndex < list.value.length - 1 ? list.value[currentIndex + 1].id : 0
|
||||
|
||||
drawerVisible.value = true
|
||||
}
|
||||
|
||||
/** 处理上一条/下一条切换 */
|
||||
const handlePrevNextClick = (type: 'prev' | 'next') => {
|
||||
if (customerId.value === undefined) return
|
||||
|
||||
handlePrevNext(type, {
|
||||
list: list.value,
|
||||
currentId: customerId.value,
|
||||
onUpdateIds: ({ currentId, prevId: newPrevId, nextId: newNextId }) => {
|
||||
customerId.value = currentId
|
||||
prevId.value = newPrevId
|
||||
nextId.value = newNextId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 打开转公海弹窗 */
|
||||
const openTransferForm = () => {
|
||||
if (multipleSelection.value.length === 0) {
|
||||
|
|
|
|||
|
|
@ -281,13 +281,7 @@
|
|||
|
||||
<!-- 客户详情抽屉 -->
|
||||
<el-drawer v-model="drawerVisible" size="80%" :destroy-on-close="true" :with-header="false" :show-close="true">
|
||||
<CustomerDetail
|
||||
:customer-id="customerId"
|
||||
:prev-id="prevId"
|
||||
:next-id="nextId"
|
||||
@prev="handlePrevNextClick('prev')"
|
||||
@next="handlePrevNextClick('next')"
|
||||
/>
|
||||
<CustomerDetail :customer-id="customerId" />
|
||||
</el-drawer>
|
||||
|
||||
<!-- 转公海弹窗 -->
|
||||
|
|
@ -299,7 +293,6 @@
|
|||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
import { buildTree } from '@/utils/tree'
|
||||
import { handlePrevNext } from '@/utils/crm'
|
||||
import { CustomerInforApi, CustomerInforVO } from '@/api/crm/customer/customer'
|
||||
import CustomerDetail from '@/views/crm/components/Customer/Detail.vue'
|
||||
import TransferForm from '@/views/crm/components/Transfer/TransferForm.vue'
|
||||
|
|
@ -349,8 +342,6 @@ let customerSourceOptions = ref<any>()
|
|||
let customerTypeOptions = ref<any>()
|
||||
const drawerVisible = ref(false) // 抽屉是否显示
|
||||
const customerId = ref<number>() // 当前查看的客户ID
|
||||
const prevId = ref<number>(0) // 上一条记录ID
|
||||
const nextId = ref<number>(0) // 下一条记录ID
|
||||
const cascaderProps= {
|
||||
emitPath: false,
|
||||
}
|
||||
|
|
@ -384,31 +375,9 @@ const resetQuery = () => {
|
|||
/** 打开跟进抽屉 */
|
||||
const openInforForm = (id?: number) => {
|
||||
customerId.value = id
|
||||
// 找到当前记录在列表中的索引
|
||||
const currentIndex = list.value.findIndex(item => item.id === id)
|
||||
|
||||
// 获取上一条和下一条记录的ID
|
||||
prevId.value = currentIndex > 0 ? list.value[currentIndex - 1].id : 0
|
||||
nextId.value = currentIndex < list.value.length - 1 ? list.value[currentIndex + 1].id : 0
|
||||
|
||||
drawerVisible.value = true
|
||||
}
|
||||
|
||||
/** 处理上一条/下一条切换 */
|
||||
const handlePrevNextClick = (type: 'prev' | 'next') => {
|
||||
if (customerId.value === undefined) return
|
||||
|
||||
handlePrevNext(type, {
|
||||
list: list.value,
|
||||
currentId: customerId.value,
|
||||
onUpdateIds: ({ currentId, prevId: newPrevId, nextId: newNextId }) => {
|
||||
customerId.value = currentId
|
||||
prevId.value = newPrevId
|
||||
nextId.value = newNextId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 打开转公海弹窗 */
|
||||
const openTransferForm = () => {
|
||||
if (multipleSelection.value.length === 0) {
|
||||
|
|
|
|||
|
|
@ -280,13 +280,7 @@
|
|||
|
||||
<!-- 客户详情抽屉 -->
|
||||
<el-drawer v-model="drawerVisible" size="80%" :destroy-on-close="true" :with-header="false" :show-close="true">
|
||||
<CustomerDetail
|
||||
:customer-id="customerId"
|
||||
:prev-id="prevId"
|
||||
:next-id="nextId"
|
||||
@prev="handlePrevNextClick('prev')"
|
||||
@next="handlePrevNextClick('next')"
|
||||
/>
|
||||
<CustomerDetail :customer-id="customerId" />
|
||||
</el-drawer>
|
||||
|
||||
<!-- 转公海弹窗 -->
|
||||
|
|
@ -298,7 +292,6 @@
|
|||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
import { buildTree } from '@/utils/tree'
|
||||
import { handlePrevNext } from '@/utils/crm'
|
||||
import { CustomerInforApi, CustomerInforVO } from '@/api/crm/customer/customer'
|
||||
import CustomerDetail from '@/views/crm/components/Customer/Detail.vue'
|
||||
import TransferForm from '@/views/crm/components/Transfer/TransferForm.vue'
|
||||
|
|
@ -349,8 +342,6 @@ let customerSourceOptions = ref<any>()
|
|||
let customerTypeOptions = ref<any>()
|
||||
const drawerVisible = ref(false) // 抽屉是否显示
|
||||
const customerId = ref<number>() // 当前查看的客户ID
|
||||
const prevId = ref<number>(0) // 上一条记录ID
|
||||
const nextId = ref<number>(0) // 下一条记录ID
|
||||
const cascaderProps= {
|
||||
emitPath: false,
|
||||
}
|
||||
|
|
@ -389,31 +380,9 @@ const resetQuery = () => {
|
|||
/** 打开跟进抽屉 */
|
||||
const openInforForm = (id?: number) => {
|
||||
customerId.value = id
|
||||
// 找到当前记录在列表中的索引
|
||||
const currentIndex = list.value.findIndex(item => item.id === id)
|
||||
|
||||
// 获取上一条和下一条记录的ID
|
||||
prevId.value = currentIndex > 0 ? list.value[currentIndex - 1].id : 0
|
||||
nextId.value = currentIndex < list.value.length - 1 ? list.value[currentIndex + 1].id : 0
|
||||
|
||||
drawerVisible.value = true
|
||||
}
|
||||
|
||||
/** 处理上一条/下一条切换 */
|
||||
const handlePrevNextClick = (type: 'prev' | 'next') => {
|
||||
if (customerId.value === undefined) return
|
||||
|
||||
handlePrevNext(type, {
|
||||
list: list.value,
|
||||
currentId: customerId.value,
|
||||
onUpdateIds: ({ currentId, prevId: newPrevId, nextId: newNextId }) => {
|
||||
customerId.value = currentId
|
||||
prevId.value = newPrevId
|
||||
nextId.value = newNextId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 打开转公海弹窗 */
|
||||
const openTransferForm = () => {
|
||||
if (multipleSelection.value.length === 0) {
|
||||
|
|
|
|||
|
|
@ -280,13 +280,7 @@
|
|||
|
||||
<!-- 客户详情抽屉 -->
|
||||
<el-drawer v-model="drawerVisible" size="80%" :destroy-on-close="true" :with-header="false" :show-close="true">
|
||||
<CustomerDetail
|
||||
:customer-id="customerId"
|
||||
:prev-id="prevId"
|
||||
:next-id="nextId"
|
||||
@prev="handlePrevNextClick('prev')"
|
||||
@next="handlePrevNextClick('next')"
|
||||
/>
|
||||
<CustomerDetail :customer-id="customerId" />
|
||||
</el-drawer>
|
||||
|
||||
<!-- 转公海弹窗 -->
|
||||
|
|
@ -298,7 +292,6 @@
|
|||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
import { buildTree } from '@/utils/tree'
|
||||
import { handlePrevNext } from '@/utils/crm'
|
||||
import { CustomerInforApi, CustomerInforVO } from '@/api/crm/customer/customer'
|
||||
import CustomerDetail from '@/views/crm/components/Customer/Detail.vue'
|
||||
import TransferForm from '@/views/crm/components/Transfer/TransferForm.vue'
|
||||
|
|
@ -349,8 +342,6 @@ let customerSourceOptions = ref<any>()
|
|||
let customerTypeOptions = ref<any>()
|
||||
const drawerVisible = ref(false) // 抽屉是否显示
|
||||
const customerId = ref<number>() // 当前查看的客户ID
|
||||
const prevId = ref<number>(0) // 上一条记录ID
|
||||
const nextId = ref<number>(0) // 下一条记录ID
|
||||
const cascaderProps= {
|
||||
emitPath: false,
|
||||
}
|
||||
|
|
@ -389,31 +380,9 @@ const resetQuery = () => {
|
|||
/** 打开跟进抽屉 */
|
||||
const openInforForm = (id?: number) => {
|
||||
customerId.value = id
|
||||
// 找到当前记录在列表中的索引
|
||||
const currentIndex = list.value.findIndex(item => item.id === id)
|
||||
|
||||
// 获取上一条和下一条记录的ID
|
||||
prevId.value = currentIndex > 0 ? list.value[currentIndex - 1].id : 0
|
||||
nextId.value = currentIndex < list.value.length - 1 ? list.value[currentIndex + 1].id : 0
|
||||
|
||||
drawerVisible.value = true
|
||||
}
|
||||
|
||||
/** 处理上一条/下一条切换 */
|
||||
const handlePrevNextClick = (type: 'prev' | 'next') => {
|
||||
if (customerId.value === undefined) return
|
||||
|
||||
handlePrevNext(type, {
|
||||
list: list.value,
|
||||
currentId: customerId.value,
|
||||
onUpdateIds: ({ currentId, prevId: newPrevId, nextId: newNextId }) => {
|
||||
customerId.value = currentId
|
||||
prevId.value = newPrevId
|
||||
nextId.value = newNextId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 打开转公海弹窗 */
|
||||
const openTransferForm = () => {
|
||||
if (multipleSelection.value.length === 0) {
|
||||
|
|
|
|||
|
|
@ -277,13 +277,7 @@
|
|||
|
||||
<!-- 客户详情抽屉 -->
|
||||
<el-drawer v-model="drawerVisible" size="80%" :destroy-on-close="true" :with-header="false" :show-close="true">
|
||||
<CustomerDetail
|
||||
:customer-id="customerId"
|
||||
:prev-id="prevId"
|
||||
:next-id="nextId"
|
||||
@prev="handlePrevNextClick('prev')"
|
||||
@next="handlePrevNextClick('next')"
|
||||
/>
|
||||
<CustomerDetail :customer-id="customerId" />
|
||||
</el-drawer>
|
||||
|
||||
<!-- 转公海弹窗 -->
|
||||
|
|
@ -295,7 +289,6 @@
|
|||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
import { buildTree } from '@/utils/tree'
|
||||
import { handlePrevNext } from '@/utils/crm'
|
||||
import { CustomerInforApi, CustomerInforVO } from '@/api/crm/customer/customer'
|
||||
import CustomerDetail from '@/views/crm/components/Customer/Detail.vue'
|
||||
import TransferForm from '@/views/crm/components/Transfer/TransferForm.vue'
|
||||
|
|
@ -345,8 +338,6 @@ let customerSourceOptions = ref<any>()
|
|||
let customerTypeOptions = ref<any>()
|
||||
const drawerVisible = ref(false) // 抽屉是否显示
|
||||
const customerId = ref<number>() // 当前查看的客户ID
|
||||
const prevId = ref<number>(0) // 上一条记录ID
|
||||
const nextId = ref<number>(0) // 下一条记录ID
|
||||
const cascaderProps= {
|
||||
emitPath: false,
|
||||
}
|
||||
|
|
@ -381,31 +372,9 @@ const resetQuery = () => {
|
|||
/** 打开跟进抽屉 */
|
||||
const openInforForm = (id?: number) => {
|
||||
customerId.value = id
|
||||
// 找到当前记录在列表中的索引
|
||||
const currentIndex = list.value.findIndex(item => item.id === id)
|
||||
|
||||
// 获取上一条和下一条记录的ID
|
||||
prevId.value = currentIndex > 0 ? list.value[currentIndex - 1].id : 0
|
||||
nextId.value = currentIndex < list.value.length - 1 ? list.value[currentIndex + 1].id : 0
|
||||
|
||||
drawerVisible.value = true
|
||||
}
|
||||
|
||||
/** 处理上一条/下一条切换 */
|
||||
const handlePrevNextClick = (type: 'prev' | 'next') => {
|
||||
if (customerId.value === undefined) return
|
||||
|
||||
handlePrevNext(type, {
|
||||
list: list.value,
|
||||
currentId: customerId.value,
|
||||
onUpdateIds: ({ currentId, prevId: newPrevId, nextId: newNextId }) => {
|
||||
customerId.value = currentId
|
||||
prevId.value = newPrevId
|
||||
nextId.value = newNextId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 打开转公海弹窗 */
|
||||
const openTransferForm = () => {
|
||||
if (multipleSelection.value.length === 0) {
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@
|
|||
:inline="true"
|
||||
label-width="68px"
|
||||
>
|
||||
<el-form-item label="客户名称" prop="customerName">
|
||||
<el-form-item label="客户姓名" prop="customerName">
|
||||
<el-input
|
||||
v-model="queryParams.customerName"
|
||||
placeholder="请输入客户名称"
|
||||
placeholder="请输入客户姓名"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
class="!w-120px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号码" prop="mobile">
|
||||
|
|
@ -22,17 +22,10 @@
|
|||
v-model="queryParams.mobile"
|
||||
placeholder="请输入手机号码"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="座机号码" prop="telephone">
|
||||
<el-input
|
||||
v-model="queryParams.telephone"
|
||||
placeholder="请输入座机号码"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
class="!w-120px"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="客户类型" prop="customerTypeId">
|
||||
<el-cascader
|
||||
v-model="queryParams.customerTypeId"
|
||||
|
|
@ -62,8 +55,9 @@
|
|||
<el-form-item label="跟进状态" prop="followStatus">
|
||||
<el-select
|
||||
v-model="queryParams.followStatus"
|
||||
placeholder="请选择跟进状态"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
class="!w-120px"
|
||||
>
|
||||
<el-option
|
||||
v-for="dict in followStatusList"
|
||||
|
|
|
|||
|
|
@ -265,13 +265,7 @@
|
|||
</ContentWrap>
|
||||
<!-- 客户详情抽屉 -->
|
||||
<el-drawer v-model="drawerVisible" size="80%" :destroy-on-close="true" :with-header="false" :show-close="true">
|
||||
<CustomerDetail
|
||||
:customer-id="customerId"
|
||||
:prev-id="prevId"
|
||||
:next-id="nextId"
|
||||
@prev="handlePrevNextClick('prev')"
|
||||
@next="handlePrevNextClick('next')"
|
||||
/>
|
||||
<CustomerDetail :customer-id="customerId" />
|
||||
</el-drawer>
|
||||
|
||||
<!-- 分配弹窗 -->
|
||||
|
|
@ -281,8 +275,7 @@
|
|||
<script setup lang="ts">
|
||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
import { buildTree } from '@/utils/tree'
|
||||
import { handlePrevNext } from '@/utils/crm'
|
||||
import { buildTree } from '@/utils/tree'
|
||||
import { CustomerInforApi, CustomerInforVO } from '@/api/crm/customer/customer'
|
||||
import { useCrmStore } from '@/store/modules/crm'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
|
@ -309,8 +302,6 @@ let customerTypeOptions = ref<any>()
|
|||
|
||||
const drawerVisible = ref(false) // 抽屉是否显示
|
||||
const customerId = ref<number>() // 当前查看的客户ID
|
||||
const prevId = ref<number>(0) // 上一条记录ID
|
||||
const nextId = ref<number>(0) // 下一条记录ID
|
||||
const multipleSelection = ref<CustomerInforVO[]>([])
|
||||
const formRef = ref() // 分配表单的 Ref
|
||||
|
||||
|
|
@ -367,13 +358,6 @@ const resetQuery = () => {
|
|||
/** 打开跟进抽屉 */
|
||||
const openInforForm = (id?: number) => {
|
||||
customerId.value = id
|
||||
// 找到当前记录在列表中的索引
|
||||
const currentIndex = list.value.findIndex(item => item.id === id)
|
||||
|
||||
// 获取上一条和下一条记录的ID
|
||||
prevId.value = currentIndex > 0 ? list.value[currentIndex - 1].id : 0
|
||||
nextId.value = currentIndex < list.value.length - 1 ? list.value[currentIndex + 1].id : 0
|
||||
|
||||
drawerVisible.value = true
|
||||
}
|
||||
/** 打开分配弹窗 */
|
||||
|
|
@ -433,19 +417,4 @@ const handleReceive = async () => {
|
|||
message.error('领取失败')
|
||||
}
|
||||
}
|
||||
|
||||
/** 处理上一条/下一条切换 */
|
||||
const handlePrevNextClick = (type: 'prev' | 'next') => {
|
||||
if (customerId.value === undefined) return
|
||||
|
||||
handlePrevNext(type, {
|
||||
list: list.value,
|
||||
currentId: customerId.value,
|
||||
onUpdateIds: ({ currentId, prevId: newPrevId, nextId: newNextId }) => {
|
||||
customerId.value = currentId
|
||||
prevId.value = newPrevId
|
||||
nextId.value = newNextId
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -265,13 +265,7 @@
|
|||
</ContentWrap>
|
||||
<!-- 客户详情抽屉 -->
|
||||
<el-drawer v-model="drawerVisible" size="80%" :destroy-on-close="true" :with-header="false" :show-close="true">
|
||||
<CustomerDetail
|
||||
:customer-id="customerId"
|
||||
:prev-id="prevId"
|
||||
:next-id="nextId"
|
||||
@prev="handlePrevNextClick('prev')"
|
||||
@next="handlePrevNextClick('next')"
|
||||
/>
|
||||
<CustomerDetail :customer-id="customerId" />
|
||||
</el-drawer>
|
||||
|
||||
<!-- 分配弹窗 -->
|
||||
|
|
@ -281,8 +275,7 @@
|
|||
<script setup lang="ts">
|
||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
import { buildTree } from '@/utils/tree'
|
||||
import { handlePrevNext } from '@/utils/crm'
|
||||
import { buildTree } from '@/utils/tree'
|
||||
import { CustomerInforApi, CustomerInforVO } from '@/api/crm/customer/customer'
|
||||
import { useCrmStore } from '@/store/modules/crm'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
|
@ -310,8 +303,6 @@ let customerTypeOptions = ref<any>()
|
|||
|
||||
const drawerVisible = ref(false) // 抽屉是否显示
|
||||
const customerId = ref<number>() // 当前查看的客户ID
|
||||
const prevId = ref<number>(0) // 上一条记录ID
|
||||
const nextId = ref<number>(0) // 下一条记录ID
|
||||
const multipleSelection = ref<CustomerInforVO[]>([])
|
||||
const formRef = ref() // 分配表单的 Ref
|
||||
|
||||
|
|
@ -368,13 +359,6 @@ const resetQuery = () => {
|
|||
/** 打开跟进抽屉 */
|
||||
const openInforForm = (id?: number) => {
|
||||
customerId.value = id
|
||||
// 找到当前记录在列表中的索引
|
||||
const currentIndex = list.value.findIndex(item => item.id === id)
|
||||
|
||||
// 获取上一条和下一条记录的ID
|
||||
prevId.value = currentIndex > 0 ? list.value[currentIndex - 1].id : 0
|
||||
nextId.value = currentIndex < list.value.length - 1 ? list.value[currentIndex + 1].id : 0
|
||||
|
||||
drawerVisible.value = true
|
||||
}
|
||||
/** 打开分配弹窗 */
|
||||
|
|
@ -434,19 +418,4 @@ const handleReceive = async () => {
|
|||
message.error('领取失败')
|
||||
}
|
||||
}
|
||||
|
||||
/** 处理上一条/下一条切换 */
|
||||
const handlePrevNextClick = (type: 'prev' | 'next') => {
|
||||
if (customerId.value === undefined) return
|
||||
|
||||
handlePrevNext(type, {
|
||||
list: list.value,
|
||||
currentId: customerId.value,
|
||||
onUpdateIds: ({ currentId, prevId: newPrevId, nextId: newNextId }) => {
|
||||
customerId.value = currentId
|
||||
prevId.value = newPrevId
|
||||
nextId.value = newNextId
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
Loading…
Reference in New Issue