Browse Source

📖 CRM:线索的跟进逻辑

YunaiV 1 year ago
parent
commit
04a42bc6d4

+ 0 - 5
src/api/crm/backlog/index.ts

@@ -6,11 +6,6 @@ export const getTodayCustomerCount = async () => {
   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. 获得分配给我的客户数量
 export const getFollowCustomerCount = async () => {
   return await request.get({ url: '/crm/customer/follow-customer-count' })

+ 7 - 2
src/api/crm/clue/index.ts

@@ -68,6 +68,11 @@ export const transferClue = async (data: TransferReqVO) => {
 }
 
 // 线索转化为客户
-export const transformClue = async (ids: number[]) => {
-  return await request.put({ url: '/crm/clue/transform?ids=' + ids.join(',') })
+export const transformClue = async (id: number) => {
+  return await request.put({ url: '/crm/clue/transform', params: { id } })
+}
+
+// 获得分配给我的、待跟进的线索数量
+export const getFollowClueCount = async () => {
+  return await request.get({ url: '/crm/clue/follow-count' })
 }

+ 49 - 21
src/views/crm/backlog/tables/FollowLeads.vue → src/views/crm/backlog/components/ClueFollowList.vue

@@ -1,5 +1,3 @@
-<!-- TODO: dhb52 待Clue页面更新后同步更新 -->
-<!-- WHERE transformStatus = 0 AND followUpStatus = ? -->
 <template>
   <ContentWrap>
     <div class="pb-5 text-xl">分配给我的线索</div>
@@ -31,30 +29,40 @@
   <!-- 列表 -->
   <ContentWrap>
     <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="transformStatus">
+      <el-table-column label="线索名称" align="center" prop="name" fixed="left" width="120">
         <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>
       </el-table-column>
-      <el-table-column label="跟进状态" align="center" prop="followUpStatus">
+      <el-table-column label="线索来源" align="center" prop="source" width="100">
         <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>
       </el-table-column>
-      <el-table-column label="线索名称" align="center" prop="name" />
-      <el-table-column label="客户id" align="center" prop="customerId" />
       <el-table-column
-        label="下次联系时间"
+        :formatter="dateFormatter"
         align="center"
+        label="下次联系时间"
         prop="contactNextTime"
-        :formatter="dateFormatter"
         width="180px"
       />
-      <el-table-column label="电话" align="center" prop="telephone" />
-      <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 align="center" label="备注" prop="remark" width="200" />
       <el-table-column
         label="最后跟进时间"
         align="center"
@@ -62,7 +70,16 @@
         :formatter="dateFormatter"
         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
         label="创建时间"
         align="center"
@@ -70,6 +87,7 @@
         :formatter="dateFormatter"
         width="180px"
       />
+      <el-table-column align="center" label="创建人" prop="creatorName" width="100px" />
     </el-table>
     <!-- 分页 -->
     <Pagination
@@ -80,13 +98,14 @@
     />
   </ContentWrap>
 </template>
-
-<script setup lang="ts" name="FollowLeads">
+<script setup lang="ts">
 import * as ClueApi from '@/api/crm/clue'
 import { DICT_TYPE } from '@/utils/dict'
 import { dateFormatter } from '@/utils/formatTime'
 import { FOLLOWUP_STATUS } from './common'
 
+defineOptions({ name: 'CrmClueFollowList' })
+
 const loading = ref(true) // 列表的加载中
 const total = ref(0) // 列表的总页数
 const list = ref([]) // 列表的数据
@@ -94,7 +113,7 @@ const queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
   followUpStatus: false,
-  transformStatus: false // 固定为【未转移】
+  transformStatus: false
 })
 const queryFormRef = ref() // 搜索的表单
 
@@ -116,10 +135,19 @@ const handleQuery = () => {
   getList()
 }
 
+/** 打开线索详情 */
+const { push } = useRouter()
+const openDetail = (id: number) => {
+  push({ name: 'CrmClueDetail', params: { id } })
+}
+
+/** 激活时 */
+onActivated(async () => {
+  await getList()
+})
+
 /** 初始化 **/
 onMounted(() => {
   getList()
 })
 </script>
-
-<style scoped></style>

+ 38 - 0
src/views/crm/backlog/components/common.ts

@@ -0,0 +1,38 @@
+/** 跟进状态 */
+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 }
+]

+ 56 - 39
src/views/crm/backlog/index.vue

@@ -5,24 +5,24 @@
         <div
           v-for="(item, index) in leftSides"
           :key="index"
-          :class="leftType == item.infoType ? 'side-item-select' : 'side-item-default'"
+          :class="leftMenu == item.menu ? 'side-item-select' : 'side-item-default'"
           class="side-item"
           @click="sideClick(item)"
         >
           {{ item.name }}
-          <el-badge v-if="item.msgCount > 0" :max="99" :value="item.msgCount" />
+          <el-badge v-if="item.count > 0" :max="99" :value="item.count" />
         </div>
       </div>
     </el-col>
     <el-col :span="20" :xs="24">
-      <TodayCustomer v-if="leftType === 'todayCustomer'" />
-      <FollowLeads v-if="leftType === 'followLeads'" />
-      <CheckContract v-if="leftType === 'checkContract'" />
-      <CheckReceivables v-if="leftType === 'checkReceivables'" />
-      <EndContract v-if="leftType === 'endContract'" />
-      <FollowCustomer v-if="leftType === 'followCustomer'" />
-      <PutInPoolRemind v-if="leftType === 'putInPoolRemind'" />
-      <RemindReceivables v-if="leftType === 'remindReceivables'" />
+      <TodayCustomer v-if="leftMenu === 'todayCustomer'" />
+      <ClueFollowList v-if="leftMenu === 'clueFollow'" />
+      <CheckContract v-if="leftMenu === 'checkContract'" />
+      <CheckReceivables v-if="leftMenu === 'checkReceivables'" />
+      <EndContract v-if="leftMenu === 'endContract'" />
+      <FollowCustomer v-if="leftMenu === 'followCustomer'" />
+      <PutInPoolRemind v-if="leftMenu === 'putInPoolRemind'" />
+      <RemindReceivables v-if="leftMenu === 'remindReceivables'" />
     </el-col>
   </el-row>
 </template>
@@ -33,15 +33,18 @@ import CheckContract from './tables/CheckContract.vue'
 import CheckReceivables from './tables/CheckReceivables.vue'
 import EndContract from './tables/EndContract.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 RemindReceivables from './tables/RemindReceivables.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 followLeadsCountRef = ref(0)
+const clueFollowCount = ref(0)
 const followCustomerCountRef = ref(0)
 const putInPoolCustomerRemindCountRef = ref(0)
 const checkContractCountRef = ref(0)
@@ -52,61 +55,75 @@ const endContractCountRef = ref(0)
 const leftSides = ref([
   {
     name: '今日需联系客户',
-    infoType: 'todayCustomer',
-    msgCount: todayCustomerCountRef
+    menu: 'todayCustomer',
+    count: todayCustomerCountRef
   },
   {
     name: '分配给我的线索',
-    infoType: 'followLeads',
-    msgCount: followLeadsCountRef
+    menu: 'clueFollow',
+    count: clueFollowCount
   },
   {
     name: '分配给我的客户',
-    infoType: 'followCustomer',
-    msgCount: followCustomerCountRef
+    menu: 'followCustomer',
+    count: followCustomerCountRef
   },
   {
     name: '待进入公海的客户',
-    infoType: 'putInPoolRemind',
-    msgCount: putInPoolCustomerRemindCountRef
+    menu: 'putInPoolRemind',
+    count: putInPoolCustomerRemindCountRef
   },
   {
     name: '待审核合同',
-    infoType: 'checkContract',
-    msgCount: checkContractCountRef
+    menu: 'checkContract',
+    count: checkContractCountRef
   },
   {
     name: '待审核回款',
-    infoType: 'checkReceivables',
-    msgCount: checkReceivablesCountRef
+    menu: 'checkReceivables',
+    count: checkReceivablesCountRef
   },
   {
     name: '待回款提醒',
-    infoType: 'remindReceivables',
-    msgCount: remindReceivablesCountRef
+    menu: 'remindReceivables',
+    count: remindReceivablesCountRef
   },
   {
     name: '即将到期的合同',
-    infoType: 'endContract',
-    msgCount: endContractCountRef
+    menu: 'endContract',
+    count: endContractCountRef
   }
 ])
 
 /** 侧边点击 */
 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 () => {
-  BacklogApi.getTodayCustomerCount().then(count => todayCustomerCountRef.value = count)
-  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)
+  getCount()
 })
 </script>
 

+ 2 - 2
src/views/crm/clue/detail/index.vue

@@ -18,7 +18,7 @@
     >
       转化为客户
     </el-button>
-    <el-button type="success" disabled>已转化客户</el-button>
+    <el-button v-else type="success" disabled>已转化客户</el-button>
   </ClueDetailsHeader>
   <el-col>
     <el-tabs>
@@ -97,7 +97,7 @@ const transfer = () => {
 /** 转化为客户 */
 const handleTransform = async () => {
   await message.confirm(`确定将【${clue.value.name}】转化为客户吗?`)
-  await ClueApi.transformClue([clueId.value])
+  await ClueApi.transformClue(clueId.value)
   message.success(`转化客户【${clue.value.name}】成功`)
   await getClue()
 }