Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
04a42bc6
authored
Feb 19, 2024
by
YunaiV
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
📖
CRM:线索的跟进逻辑
parent
0ae6139e
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
152 additions
and
69 deletions
+152
-69
src/api/crm/backlog/index.ts
+0
-5
src/api/crm/clue/index.ts
+7
-2
src/views/crm/backlog/components/ClueFollowList.vue
+49
-21
src/views/crm/backlog/components/common.ts
+38
-0
src/views/crm/backlog/index.vue
+56
-39
src/views/crm/clue/detail/index.vue
+2
-2
No files found.
src/api/crm/backlog/index.ts
View file @
04a42bc6
...
@@ -6,11 +6,6 @@ export const getTodayCustomerCount = async () => {
...
@@ -6,11 +6,6 @@ export const getTodayCustomerCount = async () => {
return
await
request
.
get
({
url
:
'/crm/customer/today-customer-count'
})
return
await
request
.
get
({
url
:
'/crm/customer/today-customer-count'
})
}
}
// 2. 获得分配给我的线索数量
export
const
getFollowLeadsCount
=
async
()
=>
{
return
await
request
.
get
({
url
:
'/crm/clue/follow-leads-count'
})
}
// 3. 获得分配给我的客户数量
// 3. 获得分配给我的客户数量
export
const
getFollowCustomerCount
=
async
()
=>
{
export
const
getFollowCustomerCount
=
async
()
=>
{
return
await
request
.
get
({
url
:
'/crm/customer/follow-customer-count'
})
return
await
request
.
get
({
url
:
'/crm/customer/follow-customer-count'
})
...
...
src/api/crm/clue/index.ts
View file @
04a42bc6
...
@@ -68,6 +68,11 @@ export const transferClue = async (data: TransferReqVO) => {
...
@@ -68,6 +68,11 @@ export const transferClue = async (data: TransferReqVO) => {
}
}
// 线索转化为客户
// 线索转化为客户
export
const
transformClue
=
async
(
ids
:
number
[])
=>
{
export
const
transformClue
=
async
(
id
:
number
)
=>
{
return
await
request
.
put
({
url
:
'/crm/clue/transform?ids='
+
ids
.
join
(
','
)
})
return
await
request
.
put
({
url
:
'/crm/clue/transform'
,
params
:
{
id
}
})
}
// 获得分配给我的、待跟进的线索数量
export
const
getFollowClueCount
=
async
()
=>
{
return
await
request
.
get
({
url
:
'/crm/clue/follow-count'
})
}
}
src/views/crm/backlog/
tables/FollowLeads
.vue
→
src/views/crm/backlog/
components/ClueFollowList
.vue
View file @
04a42bc6
<!-- TODO: dhb52 待Clue页面更新后同步更新 -->
<!-- WHERE transformStatus = 0 AND followUpStatus = ? -->
<
template
>
<
template
>
<ContentWrap>
<ContentWrap>
<div
class=
"pb-5 text-xl"
>
分配给我的线索
</div>
<div
class=
"pb-5 text-xl"
>
分配给我的线索
</div>
...
@@ -31,30 +29,40 @@
...
@@ -31,30 +29,40 @@
<!-- 列表 -->
<!-- 列表 -->
<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=
"id"
/>
<el-table-column
label=
"线索名称"
align=
"center"
prop=
"name"
fixed=
"left"
width=
"120"
>
<el-table-column
label=
"转化状态"
align=
"center"
prop=
"transformStatus"
>
<template
#
default=
"scope"
>
<template
#
default=
"scope"
>
<dict-tag
:type=
"DICT_TYPE.INFRA_BOOLEAN_STRING"
:value=
"scope.row.transformStatus"
/>
<el-link
:underline=
"false"
type=
"primary"
@
click=
"openDetail(scope.row.id)"
>
{{
scope
.
row
.
name
}}
</el-link>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
<el-table-column
label=
"
跟进状态"
align=
"center"
prop=
"followUpStatus
"
>
<el-table-column
label=
"
线索来源"
align=
"center"
prop=
"source"
width=
"100
"
>
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<dict-tag
:type=
"DICT_TYPE.INFRA_BOOLEAN_STRING"
:value=
"scope.row.followUpStatus"
/>
<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=
"telephone"
width=
"130"
/>
<el-table-column
label=
"邮箱"
align=
"center"
prop=
"email"
width=
"180"
/>
<el-table-column
label=
"地址"
align=
"center"
prop=
"detailAddress"
width=
"180"
/>
<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
align=
"center"
label=
"客户级别"
prop=
"level"
width=
"135"
>
<
template
#
default=
"scope"
>
<dict-tag
:type=
"DICT_TYPE.CRM_CUSTOMER_LEVEL"
:value=
"scope.row.level"
/>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
<el-table-column
label=
"线索名称"
align=
"center"
prop=
"name"
/>
<el-table-column
label=
"客户id"
align=
"center"
prop=
"customerId"
/>
<el-table-column
<el-table-column
label=
"下次联系时间
"
:formatter=
"dateFormatter
"
align=
"center"
align=
"center"
label=
"下次联系时间"
prop=
"contactNextTime"
prop=
"contactNextTime"
:formatter=
"dateFormatter"
width=
"180px"
width=
"180px"
/>
/>
<el-table-column
label=
"电话"
align=
"center"
prop=
"telephone"
/>
<el-table-column
align=
"center"
label=
"备注"
prop=
"remark"
width=
"200"
/>
<el-table-column
label=
"手机号"
align=
"center"
prop=
"mobile"
/>
<el-table-column
label=
"地址"
align=
"center"
prop=
"address"
/>
<el-table-column
label=
"负责人"
align=
"center"
prop=
"ownerUserId"
/>
<el-table-column
<el-table-column
label=
"最后跟进时间"
label=
"最后跟进时间"
align=
"center"
align=
"center"
...
@@ -62,7 +70,16 @@
...
@@ -62,7 +70,16 @@
:formatter=
"dateFormatter"
:formatter=
"dateFormatter"
width=
"180px"
width=
"180px"
/>
/>
<el-table-column
label=
"备注"
align=
"center"
prop=
"remark"
/>
<el-table-column
align=
"center"
label=
"最后跟进记录"
prop=
"contactLastContent"
width=
"200"
/>
<el-table-column
align=
"center"
label=
"负责人"
prop=
"ownerUserName"
width=
"100px"
/>
<el-table-column
align=
"center"
label=
"所属部门"
prop=
"ownerUserDeptName"
width=
"100"
/>
<el-table-column
label=
"更新时间"
align=
"center"
prop=
"updateTime"
:formatter=
"dateFormatter"
width=
"180px"
/>
<el-table-column
<el-table-column
label=
"创建时间"
label=
"创建时间"
align=
"center"
align=
"center"
...
@@ -70,6 +87,7 @@
...
@@ -70,6 +87,7 @@
:formatter=
"dateFormatter"
:formatter=
"dateFormatter"
width=
"180px"
width=
"180px"
/>
/>
<el-table-column
align=
"center"
label=
"创建人"
prop=
"creatorName"
width=
"100px"
/>
</el-table>
</el-table>
<!-- 分页 -->
<!-- 分页 -->
<Pagination
<Pagination
...
@@ -80,13 +98,14 @@
...
@@ -80,13 +98,14 @@
/>
/>
</ContentWrap>
</ContentWrap>
</template>
</template>
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
name=
"FollowLeads"
>
import
*
as
ClueApi
from
'@/api/crm/clue'
import
*
as
ClueApi
from
'@/api/crm/clue'
import
{
DICT_TYPE
}
from
'@/utils/dict'
import
{
DICT_TYPE
}
from
'@/utils/dict'
import
{
dateFormatter
}
from
'@/utils/formatTime'
import
{
dateFormatter
}
from
'@/utils/formatTime'
import
{
FOLLOWUP_STATUS
}
from
'./common'
import
{
FOLLOWUP_STATUS
}
from
'./common'
defineOptions
({
name
:
'CrmClueFollowList'
})
const
loading
=
ref
(
true
)
// 列表的加载中
const
loading
=
ref
(
true
)
// 列表的加载中
const
total
=
ref
(
0
)
// 列表的总页数
const
total
=
ref
(
0
)
// 列表的总页数
const
list
=
ref
([])
// 列表的数据
const
list
=
ref
([])
// 列表的数据
...
@@ -94,7 +113,7 @@ const queryParams = reactive({
...
@@ -94,7 +113,7 @@ const queryParams = reactive({
pageNo
:
1
,
pageNo
:
1
,
pageSize
:
10
,
pageSize
:
10
,
followUpStatus
:
false
,
followUpStatus
:
false
,
transformStatus
:
false
// 固定为【未转移】
transformStatus
:
false
})
})
const
queryFormRef
=
ref
()
// 搜索的表单
const
queryFormRef
=
ref
()
// 搜索的表单
...
@@ -116,10 +135,19 @@ const handleQuery = () => {
...
@@ -116,10 +135,19 @@ const handleQuery = () => {
getList
()
getList
()
}
}
/** 打开线索详情 */
const
{
push
}
=
useRouter
()
const
openDetail
=
(
id
:
number
)
=>
{
push
({
name
:
'CrmClueDetail'
,
params
:
{
id
}
})
}
/** 激活时 */
onActivated
(
async
()
=>
{
await
getList
()
})
/** 初始化 **/
/** 初始化 **/
onMounted
(()
=>
{
onMounted
(()
=>
{
getList
()
getList
()
})
})
</
script
>
</
script
>
<
style
scoped
></
style
>
src/views/crm/backlog/components/common.ts
0 → 100644
View file @
04a42bc6
/** 跟进状态 */
export
const
FOLLOWUP_STATUS
=
[
{
label
:
'待跟进'
,
value
:
false
},
{
label
:
'已跟进'
,
value
:
true
}
]
/** 归属范围 */
export
const
SCENE_TYPES
=
[
{
label
:
'我负责的'
,
value
:
1
},
{
label
:
'我参与的'
,
value
:
2
},
{
label
:
'下属负责的'
,
value
:
3
}
]
/** 联系状态 */
export
const
CONTACT_STATUS
=
[
{
label
:
'今日需联系'
,
value
:
1
},
{
label
:
'已逾期'
,
value
:
2
},
{
label
:
'已联系'
,
value
:
3
}
]
/** 审批状态 */
export
const
AUDIT_STATUS
=
[
{
label
:
'已审批'
,
value
:
20
},
{
label
:
'待审批'
,
value
:
10
}
]
/** 回款提醒类型 */
export
const
RECEIVABLE_REMIND_TYPE
=
[
{
label
:
'待回款'
,
value
:
1
},
{
label
:
'已逾期'
,
value
:
2
},
{
label
:
'已回款'
,
value
:
3
}
]
/** 合同过期状态 */
export
const
CONTRACT_EXPIRY_TYPE
=
[
{
label
:
'即将过期'
,
value
:
1
},
{
label
:
'已过期'
,
value
:
2
}
]
src/views/crm/backlog/index.vue
View file @
04a42bc6
...
@@ -5,24 +5,24 @@
...
@@ -5,24 +5,24 @@
<div
<div
v-for=
"(item, index) in leftSides"
v-for=
"(item, index) in leftSides"
:key=
"index"
:key=
"index"
:class=
"left
Type == item.infoType
? 'side-item-select' : 'side-item-default'"
:class=
"left
Menu == item.menu
? 'side-item-select' : 'side-item-default'"
class=
"side-item"
class=
"side-item"
@
click=
"sideClick(item)"
@
click=
"sideClick(item)"
>
>
{{
item
.
name
}}
{{
item
.
name
}}
<el-badge
v-if=
"item.
msgCount > 0"
:max=
"99"
:value=
"item.msgC
ount"
/>
<el-badge
v-if=
"item.
count > 0"
:max=
"99"
:value=
"item.c
ount"
/>
</div>
</div>
</div>
</div>
</el-col>
</el-col>
<el-col
:span=
"20"
:xs=
"24"
>
<el-col
:span=
"20"
:xs=
"24"
>
<TodayCustomer
v-if=
"left
Type
=== 'todayCustomer'"
/>
<TodayCustomer
v-if=
"left
Menu
=== 'todayCustomer'"
/>
<
FollowLeads
v-if=
"leftType === 'followLeads
'"
/>
<
ClueFollowList
v-if=
"leftMenu === 'clueFollow
'"
/>
<CheckContract
v-if=
"left
Type
=== 'checkContract'"
/>
<CheckContract
v-if=
"left
Menu
=== 'checkContract'"
/>
<CheckReceivables
v-if=
"left
Type
=== 'checkReceivables'"
/>
<CheckReceivables
v-if=
"left
Menu
=== 'checkReceivables'"
/>
<EndContract
v-if=
"left
Type
=== 'endContract'"
/>
<EndContract
v-if=
"left
Menu
=== 'endContract'"
/>
<FollowCustomer
v-if=
"left
Type
=== 'followCustomer'"
/>
<FollowCustomer
v-if=
"left
Menu
=== 'followCustomer'"
/>
<PutInPoolRemind
v-if=
"left
Type
=== 'putInPoolRemind'"
/>
<PutInPoolRemind
v-if=
"left
Menu
=== 'putInPoolRemind'"
/>
<RemindReceivables
v-if=
"left
Type
=== 'remindReceivables'"
/>
<RemindReceivables
v-if=
"left
Menu
=== 'remindReceivables'"
/>
</el-col>
</el-col>
</el-row>
</el-row>
</
template
>
</
template
>
...
@@ -33,15 +33,18 @@ import CheckContract from './tables/CheckContract.vue'
...
@@ -33,15 +33,18 @@ import CheckContract from './tables/CheckContract.vue'
import
CheckReceivables
from
'./tables/CheckReceivables.vue'
import
CheckReceivables
from
'./tables/CheckReceivables.vue'
import
EndContract
from
'./tables/EndContract.vue'
import
EndContract
from
'./tables/EndContract.vue'
import
FollowCustomer
from
'./tables/FollowCustomer.vue'
import
FollowCustomer
from
'./tables/FollowCustomer.vue'
import
FollowLeads
from
'./tables/FollowLeads
.vue'
import
ClueFollowList
from
'./components/ClueFollowList
.vue'
import
PutInPoolRemind
from
'./tables/PutInPoolRemind.vue'
import
PutInPoolRemind
from
'./tables/PutInPoolRemind.vue'
import
RemindReceivables
from
'./tables/RemindReceivables.vue'
import
RemindReceivables
from
'./tables/RemindReceivables.vue'
import
TodayCustomer
from
'./tables/TodayCustomer.vue'
import
TodayCustomer
from
'./tables/TodayCustomer.vue'
import
*
as
ClueApi
from
'@/api/crm/clue'
const
leftType
=
ref
(
'todayCustomer'
)
defineOptions
({
name
:
'CrmBacklog'
})
const
leftMenu
=
ref
(
'todayCustomer'
)
const
todayCustomerCountRef
=
ref
(
0
)
const
todayCustomerCountRef
=
ref
(
0
)
const
followLeadsCountRef
=
ref
(
0
)
const
clueFollowCount
=
ref
(
0
)
const
followCustomerCountRef
=
ref
(
0
)
const
followCustomerCountRef
=
ref
(
0
)
const
putInPoolCustomerRemindCountRef
=
ref
(
0
)
const
putInPoolCustomerRemindCountRef
=
ref
(
0
)
const
checkContractCountRef
=
ref
(
0
)
const
checkContractCountRef
=
ref
(
0
)
...
@@ -52,61 +55,75 @@ const endContractCountRef = ref(0)
...
@@ -52,61 +55,75 @@ const endContractCountRef = ref(0)
const
leftSides
=
ref
([
const
leftSides
=
ref
([
{
{
name
:
'今日需联系客户'
,
name
:
'今日需联系客户'
,
infoType
:
'todayCustomer'
,
menu
:
'todayCustomer'
,
msgC
ount
:
todayCustomerCountRef
c
ount
:
todayCustomerCountRef
},
},
{
{
name
:
'分配给我的线索'
,
name
:
'分配给我的线索'
,
infoType
:
'followLeads
'
,
menu
:
'clueFollow
'
,
msgCount
:
followLeadsCountRef
count
:
clueFollowCount
},
},
{
{
name
:
'分配给我的客户'
,
name
:
'分配给我的客户'
,
infoType
:
'followCustomer'
,
menu
:
'followCustomer'
,
msgC
ount
:
followCustomerCountRef
c
ount
:
followCustomerCountRef
},
},
{
{
name
:
'待进入公海的客户'
,
name
:
'待进入公海的客户'
,
infoType
:
'putInPoolRemind'
,
menu
:
'putInPoolRemind'
,
msgC
ount
:
putInPoolCustomerRemindCountRef
c
ount
:
putInPoolCustomerRemindCountRef
},
},
{
{
name
:
'待审核合同'
,
name
:
'待审核合同'
,
infoType
:
'checkContract'
,
menu
:
'checkContract'
,
msgC
ount
:
checkContractCountRef
c
ount
:
checkContractCountRef
},
},
{
{
name
:
'待审核回款'
,
name
:
'待审核回款'
,
infoType
:
'checkReceivables'
,
menu
:
'checkReceivables'
,
msgC
ount
:
checkReceivablesCountRef
c
ount
:
checkReceivablesCountRef
},
},
{
{
name
:
'待回款提醒'
,
name
:
'待回款提醒'
,
infoType
:
'remindReceivables'
,
menu
:
'remindReceivables'
,
msgC
ount
:
remindReceivablesCountRef
c
ount
:
remindReceivablesCountRef
},
},
{
{
name
:
'即将到期的合同'
,
name
:
'即将到期的合同'
,
infoType
:
'endContract'
,
menu
:
'endContract'
,
msgC
ount
:
endContractCountRef
c
ount
:
endContractCountRef
}
}
])
])
/** 侧边点击 */
/** 侧边点击 */
const
sideClick
=
(
item
:
any
)
=>
{
const
sideClick
=
(
item
:
any
)
=>
{
leftType
.
value
=
item
.
infoType
leftMenu
.
value
=
item
.
menu
}
const
getCount
=
()
=>
{
BacklogApi
.
getTodayCustomerCount
().
then
((
count
)
=>
(
todayCustomerCountRef
.
value
=
count
))
ClueApi
.
getFollowClueCount
().
then
((
count
)
=>
(
clueFollowCount
.
value
=
count
))
BacklogApi
.
getClueFollowListCount
().
then
((
count
)
=>
(
clueFollowCount
.
value
=
count
))
BacklogApi
.
getFollowCustomerCount
().
then
((
count
)
=>
(
followCustomerCountRef
.
value
=
count
))
BacklogApi
.
getPutInPoolCustomerRemindCount
().
then
(
(
count
)
=>
(
putInPoolCustomerRemindCountRef
.
value
=
count
)
)
BacklogApi
.
getCheckContractCount
().
then
((
count
)
=>
(
checkContractCountRef
.
value
=
count
))
BacklogApi
.
getCheckReceivablesCount
().
then
((
count
)
=>
(
checkReceivablesCountRef
.
value
=
count
))
BacklogApi
.
getRemindReceivablePlanCount
().
then
(
(
count
)
=>
(
remindReceivablesCountRef
.
value
=
count
)
)
BacklogApi
.
getEndContractCount
().
then
((
count
)
=>
(
endContractCountRef
.
value
=
count
))
}
}
/** 加载时读取待办数量 */
/** 激活时 */
onActivated
(
async
()
=>
{
getCount
()
})
/** 初始化 */
onMounted
(
async
()
=>
{
onMounted
(
async
()
=>
{
BacklogApi
.
getTodayCustomerCount
().
then
(
count
=>
todayCustomerCountRef
.
value
=
count
)
getCount
()
BacklogApi
.
getFollowLeadsCount
().
then
(
count
=>
followLeadsCountRef
.
value
=
count
)
BacklogApi
.
getFollowCustomerCount
().
then
(
count
=>
followCustomerCountRef
.
value
=
count
)
BacklogApi
.
getPutInPoolCustomerRemindCount
().
then
(
count
=>
putInPoolCustomerRemindCountRef
.
value
=
count
)
BacklogApi
.
getCheckContractCount
().
then
(
count
=>
checkContractCountRef
.
value
=
count
)
BacklogApi
.
getCheckReceivablesCount
().
then
(
count
=>
checkReceivablesCountRef
.
value
=
count
)
BacklogApi
.
getRemindReceivablePlanCount
().
then
(
count
=>
remindReceivablesCountRef
.
value
=
count
)
BacklogApi
.
getEndContractCount
().
then
(
count
=>
endContractCountRef
.
value
=
count
)
})
})
</
script
>
</
script
>
...
...
src/views/crm/clue/detail/index.vue
View file @
04a42bc6
...
@@ -18,7 +18,7 @@
...
@@ -18,7 +18,7 @@
>
>
转化为客户
转化为客户
</el-button>
</el-button>
<el-button
type=
"success"
disabled
>
已转化客户
</el-button>
<el-button
v-else
type=
"success"
disabled
>
已转化客户
</el-button>
</ClueDetailsHeader>
</ClueDetailsHeader>
<el-col>
<el-col>
<el-tabs>
<el-tabs>
...
@@ -97,7 +97,7 @@ const transfer = () => {
...
@@ -97,7 +97,7 @@ const transfer = () => {
/** 转化为客户 */
/** 转化为客户 */
const
handleTransform
=
async
()
=>
{
const
handleTransform
=
async
()
=>
{
await
message
.
confirm
(
`确定将【
${
clue
.
value
.
name
}
】转化为客户吗?`
)
await
message
.
confirm
(
`确定将【
${
clue
.
value
.
name
}
】转化为客户吗?`
)
await
ClueApi
.
transformClue
(
[
clueId
.
value
]
)
await
ClueApi
.
transformClue
(
clueId
.
value
)
message
.
success
(
`转化客户【
${
clue
.
value
.
name
}
】成功`
)
message
.
success
(
`转化客户【
${
clue
.
value
.
name
}
】成功`
)
await
getClue
()
await
getClue
()
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment