【招生用户端】 新增# 工作台:对接成交用户统计接口

main
kaeery 2025-03-05 23:11:42 +08:00
parent c57cc282fb
commit 5110a2c267
5 changed files with 143 additions and 45 deletions

View File

@ -12,15 +12,15 @@ export function convertProcessApi(params?: any) {
export function clueStatusApi(params?: any) {
return request.get({ url: '/control/clueStatistics', params })
}
// Top5
export function rankListApi(params?: any) {
return request.get({ url: '/control/top', params })
}
// 成交客户统计
export function completedCustomerListApi(params?: any) {
return request.get({ url: '/control/transactionCustomerStatistics', params })
}
// 获取所有组织以及人员信息
export function allUserListApi(params?: any) {
return request.get({ url: '/organization/getAllChildOrgInfo', params })
}
// 获取所有团队
export function allTeamListApi(params?: any) {
return request.get({ url: '/organization/getAllGroup', params })
}
// 获取所有组织
export function allOrgListApi(params?: any) {
return request.get({ url: '/organization/getAllOrg', params })
}

View File

@ -19,6 +19,7 @@ import { apiFeedbackAgreement, apiMasterWorkerApplyAgreement, apiMasterWorkerPhy
import { applyForEdit } from '@/api/finance/withdraw'
import { useCreateModal } from './useCreateModal'
import { toast, formatFileSize } from '@/utils/util'
import { postLists } from '@/api/account_center/postion'
export interface CategoryProp {
id: number
@ -311,3 +312,21 @@ export function useUploadMoreAction() {
previewPdf
}
}
export function usePositionData() {
const positionOptions = ref<any[]>([])
const postId = ref()
const fetchPostionData = async (callback?: (params: []) => void) => {
try {
const result = await postLists()
positionOptions.value = result.lists ?? []
if (result.lists.length > 0) postId.value = result.lists[0].id
callback && callback(result.lists)
} catch (error) {}
}
return {
positionOptions,
postId,
fetchPostionData
}
}

View File

@ -1,18 +1,16 @@
<template>
<div class="flex-1 w-full chart-card">
<card title="成交客户统计">
<v-charts style="height: 350px" :autoresize="true" :option="option" />
<v-charts style="height: 350px" ref="chartRef" v-loading="loading" :autoresize="true" :option="option" />
</card>
</div>
</template>
<script setup lang="ts">
import { completedCustomerListApi } from '@/api/workbench'
import card from './card.vue'
import vCharts from 'vue-echarts'
import type { IForm } from '../index.vue'
const data = [
{ name: '湛江团队', clueNumber: 52, client: 52, rate: 100 },
{ name: '广州团队', clueNumber: 8, client: 6, rate: 15 }
]
function createBarSeries(data, name, field) {
return {
name,
@ -20,9 +18,11 @@ function createBarSeries(data, name, field) {
data: data.map(item => item[field])
}
}
const chartRef = ref()
const data = ref<any[]>([])
const xAxisData = ref([])
const xAxisData = () => data.map(item => item.name)
const series = [createBarSeries(data, '客户数', 'clueNumber'), createBarSeries(data, '成交客户数', 'client')]
const series = [createBarSeries(data.value, '客户数', 'clientCount'), createBarSeries(data.value, '成交客户数', 'transactionClient')]
const option = ref({
color: ['#0E66FB', '#96B2D9'],
@ -40,7 +40,7 @@ const option = ref({
xAxis: [
{
type: 'category',
data: xAxisData()
data: xAxisData.value
}
],
yAxis: [
@ -53,7 +53,54 @@ const option = ref({
],
series
})
const loading = ref(false)
const fetchData = async (payload: IForm) => {
loading.value = true
try {
const result = await completedCustomerListApi(payload)
data.value = result.map((item: any) => {
const { clientCount, transactionClient } = item.leadToCustomerStatisticsVo
return {
name: item.organizationName,
clientCount,
transactionClient
}
})
xAxisData.value = result.map((item: any) => item.organizationName)
const allZero = data.value.every(item => item.clientCount == 0 && item.transactionClient == 0)
if (allZero) {
chartRef.value.setOption({
title: {
text: '暂无数据',
x: 'center',
y: 'center'
},
xAxis: [
{
type: 'category',
data: [],
splitLine: {
show: false
},
axisLine: {
show: false
}
}
],
legend: {
show: false
}
})
}
} catch (error) {}
loading.value = false
}
defineExpose({
fetchData
})
</script>
<style scoped lang="scss">
@media (max-width: 1000px) {
.chart-card {

View File

@ -3,45 +3,70 @@
<card title="TOP5">
<template #right>
<div class="positions">
<span class="default" :class="{ active: item.id == postId }" v-for="item in positions" :key="item.id" @click="postId = item.id">
<span
class="default"
:class="{ active: item.id == postId }"
v-for="item in positionOptions"
:key="item.id"
@click="postId = item.id"
>
{{ item.name }}
</span>
</div>
</template>
<el-table :data="tableData">
<el-table-column prop="index" label="排名" width="70" />
<el-table-column prop="name" label="负责人" width="180" />
<el-table-column prop="totalNumber" label="总数" />
</el-table>
<template v-if="tableData.length > 0">
<el-table :data="tableData" v-loading="loading">
<el-table-column prop="rank" label="排名" width="70" />
<el-table-column prop="username" label="负责人" width="180" />
<el-table-column prop="clueCount" label="总数" />
</el-table>
</template>
<template v-else>
<el-empty description="暂无数据" />
</template>
</card>
</div>
</template>
<script setup lang="ts">
import { rankListApi } from '@/api/workbench'
import card from './card.vue'
const positions = ref([
{ name: '电销', id: 5 },
{ name: '招生', id: 6 }
])
const postId = ref(5)
import type { IForm } from '../index.vue'
import { usePositionData } from '@/hooks/useCommon'
const tableData = ref([
{
index: 1,
name: 'John Brown',
totalNumber: 32
},
{
index: 2,
name: 'John Brown',
totalNumber: 32
},
{
index: 3,
name: 'John Brown',
totalNumber: 32
const { positionOptions, postId, fetchPostionData } = usePositionData()
const emit = defineEmits(['refresh'])
const tableData = ref([])
const loading = ref(false)
const fetchData = async (payload: IForm) => {
if (!positionOptions.value.length) await fetchPostionData()
if (tableData.value.length > 0) tableData.value = []
loading.value = true
try {
const newPayload = {
...payload,
post: postId.value
}
const result = await rankListApi(newPayload)
console.log(result)
tableData.value = result ?? []
} catch (error) {}
loading.value = false
}
watch(
() => postId.value,
(newVal, oldVal) => {
if (newVal !== oldVal) {
emit('refresh')
}
}
])
)
defineExpose({
fetchData
})
</script>
<style scoped lang="scss">
.rank {

View File

@ -4,10 +4,10 @@
<data-overview ref="dataOverviewRef" />
<div class="flex gap-[16px] flex-wrap">
<conversion-process-chart ref="coversionProcessChartRef" />
<converted-chart />
<converted-chart ref="convertedChartRef" />
</div>
<div class="flex gap-[16px] flex-wrap">
<rank />
<rank ref="rankRef" @refresh="refreshData" />
<clue-status-pie ref="clueStatusPieRef" />
<!-- <converted-line-chart /> -->
</div>
@ -37,6 +37,8 @@ const form = ref<IForm>({
createTimeEnd: getCurDate('end'),
userId: ''
})
const convertedChartRef = ref<InstanceType<typeof convertedChart>>()
const rankRef = ref<InstanceType<typeof rank>>()
const clueStatusPieRef = ref<InstanceType<typeof clueStatusPie>>()
const coversionProcessChartRef = ref<InstanceType<typeof conversionProcessChart>>()
const dataOverviewRef = ref<InstanceType<typeof dataOverview>>()
@ -57,6 +59,11 @@ const fetchAllData = (defaultValue?: number) => {
dataOverviewRef.value?.fetchData(form.value)
coversionProcessChartRef.value?.fetchData(form.value)
clueStatusPieRef.value?.fetchData(form.value)
rankRef.value?.fetchData(form.value)
convertedChartRef.value?.fetchData(form.value)
}
const refreshData = () => {
rankRef.value?.fetchData(form.value)
}
</script>