eight
2024-08-13 b10adc8a3fd000901836e2219fa83462694e9866
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
<!-- 数据统计 - 员工客户分析 -->
<template>
  <ContentWrap>
    <!-- 搜索工作栏 -->
    <el-form
      ref="queryFormRef"
      :inline="true"
      :model="queryParams"
      class="-mb-15px"
      label-width="68px"
    >
      <el-form-item label="时间范围" prop="orderDate">
        <el-date-picker
          v-model="queryParams.times"
          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
          :shortcuts="defaultShortcuts"
          class="!w-240px"
          end-placeholder="结束日期"
          start-placeholder="开始日期"
          type="daterange"
          value-format="YYYY-MM-DD HH:mm:ss"
          @change="handleQuery"
        />
      </el-form-item>
      <el-form-item label="时间间隔" prop="interval">
        <el-select
          v-model="queryParams.interval"
          class="!w-240px"
          placeholder="间隔类型"
          @change="handleQuery"
        >
          <el-option
            v-for="dict in getIntDictOptions(DICT_TYPE.DATE_INTERVAL)"
            :key="dict.value"
            :label="dict.label"
            :value="dict.value"
          />
        </el-select>
      </el-form-item>
      <el-form-item label="归属部门" prop="deptId">
        <el-tree-select
          v-model="queryParams.deptId"
          :data="deptList"
          :props="defaultProps"
          check-strictly
          class="!w-240px"
          node-key="id"
          placeholder="请选择归属部门"
          @change="(queryParams.userId = undefined), handleQuery()"
        />
      </el-form-item>
      <el-form-item label="员工" prop="userId">
        <el-select
          v-model="queryParams.userId"
          class="!w-240px"
          clearable
          placeholder="员工"
          @change="handleQuery"
        >
          <el-option
            v-for="(user, index) in userListByDeptId"
            :key="index"
            :label="user.nickname"
            :value="user.id"
          />
        </el-select>
      </el-form-item>
      <el-form-item>
        <el-button @click="handleQuery">
          <Icon class="mr-5px" icon="ep:search" />
          查询
        </el-button>
        <el-button @click="resetQuery">
          <Icon class="mr-5px" icon="ep:refresh" />
          重置
        </el-button>
      </el-form-item>
    </el-form>
  </ContentWrap>
 
  <!-- 客户统计 -->
  <el-col>
    <el-tabs v-model="activeTab">
      <!-- 客户总量分析 -->
      <el-tab-pane label="客户总量分析" lazy name="customerSummary">
        <CustomerSummary ref="customerSummaryRef" :query-params="queryParams" />
      </el-tab-pane>
      <!-- 客户跟进次数分析 -->
      <el-tab-pane label="客户跟进次数分析" lazy name="followUpSummary">
        <CustomerFollowUpSummary ref="followUpSummaryRef" :query-params="queryParams" />
      </el-tab-pane>
      <!-- 客户跟进方式分析 -->
      <el-tab-pane label="客户跟进方式分析" lazy name="followUpType">
        <CustomerFollowUpType ref="followUpTypeRef" :query-params="queryParams" />
      </el-tab-pane>
      <!-- 客户转化率分析 -->
      <el-tab-pane label="客户转化率分析" lazy name="conversionStat">
        <CustomerConversionStat ref="conversionStatRef" :query-params="queryParams" />
      </el-tab-pane>
      <!-- 公海客户分析 -->
      <el-tab-pane label="公海客户分析" lazy name="poolSummary">
        <CustomerPoolSummary ref="customerPoolSummaryRef" :query-params="queryParams" />
      </el-tab-pane>
      <!-- 成交周期分析 -->
      <el-tab-pane label="员工客户成交周期分析" lazy name="dealCycleByUser">
        <CustomerDealCycleByUser ref="dealCycleByUserRef" :query-params="queryParams" />
      </el-tab-pane>
      <el-tab-pane label="地区客户成交周期分析" lazy name="dealCycleByArea">
        <CustomerDealCycleByArea ref="dealCycleByAreaRef" :query-params="queryParams" />
      </el-tab-pane>
      <el-tab-pane label="产品客户成交周期分析" lazy name="dealCycleByProduct">
        <CustomerDealCycleByProduct ref="dealCycleByProductRef" :query-params="queryParams" />
      </el-tab-pane>
    </el-tabs>
  </el-col>
</template>
 
<script lang="ts" setup>
import * as DeptApi from '@/api/system/dept'
import * as UserApi from '@/api/system/user'
import { useUserStore } from '@/store/modules/user'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { beginOfDay, defaultShortcuts, endOfDay, formatDate } from '@/utils/formatTime'
import { defaultProps, handleTree } from '@/utils/tree'
import CustomerConversionStat from './components/CustomerConversionStat.vue'
import CustomerDealCycleByUser from './components/CustomerDealCycleByUser.vue'
import CustomerDealCycleByArea from './components/CustomerDealCycleByArea.vue'
import CustomerDealCycleByProduct from './components/CustomerDealCycleByProduct.vue'
import CustomerFollowUpSummary from './components/CustomerFollowUpSummary.vue'
import CustomerFollowUpType from './components/CustomerFollowUpType.vue'
import CustomerSummary from './components/CustomerSummary.vue'
import CustomerPoolSummary from './components/CustomerPoolSummary.vue'
 
defineOptions({ name: 'CrmStatisticsCustomer' })
 
const queryParams = reactive({
  interval: 2, // WEEK, 周
  deptId: useUserStore().getUser.deptId,
  userId: undefined,
  times: [
    // 默认显示最近一周的数据
    formatDate(beginOfDay(new Date(new Date().getTime() - 3600 * 1000 * 24 * 7))),
    formatDate(endOfDay(new Date(new Date().getTime() - 3600 * 1000 * 24)))
  ]
})
 
const queryFormRef = ref() // 搜索的表单
const deptList = ref<Tree[]>([]) // 部门树形结构
const userList = ref<UserApi.UserVO[]>([]) // 全量用户清单
 
/** 根据选择的部门筛选员工清单 */
const userListByDeptId = computed(() =>
  queryParams.deptId
    ? userList.value.filter((u: UserApi.UserVO) => u.deptId === queryParams.deptId)
    : []
)
 
const activeTab = ref('customerSummary') // 活跃标签
const customerSummaryRef = ref() // 1. 客户总量分析
const followUpSummaryRef = ref() // 2. 客户跟进次数分析
const followUpTypeRef = ref() // 3. 客户跟进方式分析
const conversionStatRef = ref() // 4. 客户转化率分析
const customerPoolSummaryRef = ref() // 5. 客户公海分析
const dealCycleByUserRef = ref() // 6. 成交周期分析(按员工)
const dealCycleByAreaRef = ref() // 7. 成交周期分析(按地区)
const dealCycleByProductRef = ref() // 8. 成交周期分析(按产品)
 
/** 搜索按钮操作 */
const handleQuery = () => {
  switch (activeTab.value) {
    case 'customerSummary': // 客户总量分析
      customerSummaryRef.value?.loadData?.()
      break
    case 'followUpSummary': // 客户跟进次数分析
      followUpSummaryRef.value?.loadData?.()
      break
    case 'followUpType': // 客户跟进方式分析
      followUpTypeRef.value?.loadData?.()
      break
    case 'conversionStat': // 客户转化率分析
      conversionStatRef.value?.loadData?.()
      break
    case 'poolSummary': // 公海客户分析
      customerPoolSummaryRef.value?.loadData?.()
      break
    case 'dealCycleByUser': // 成交周期分析
      dealCycleByUserRef.value?.loadData?.()
      break
    case 'dealCycleByArea': // 成交周期分析
      dealCycleByAreaRef.value?.loadData?.()
      break
    case 'dealCycleByProduct': // 成交周期分析
      dealCycleByProductRef.value?.loadData?.()
      break
  }
}
 
/** 当 activeTab 改变时,刷新当前活动的 tab */
watch(activeTab, () => {
  handleQuery()
})
 
/** 重置按钮操作 */
const resetQuery = () => {
  queryFormRef.value.resetFields()
  handleQuery()
}
 
/** 初始化 */
onMounted(async () => {
  deptList.value = handleTree(await DeptApi.getSimpleDeptList())
  userList.value = handleTree(await UserApi.getSimpleUserList())
})
</script>