【招生用户端】 修复# 工作台:切换条件查询时,线索转客户统计以及成交客户统计没反应
parent
6e1a9e0ce9
commit
6bdb7a2730
|
@ -24,3 +24,7 @@ export function subAccountDetail(params: Record<string, any>) {
|
|||
export function subAccountDelete(params: Record<string, any>) {
|
||||
return request.post({ url: '/user/sonDel', params })
|
||||
}
|
||||
// 修改账号状态
|
||||
export function subAccountUpdateStatus(params: Record<string, any>) {
|
||||
return request.post({ url: '/user/changingAccountStatus', params })
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
|
@ -96,9 +96,13 @@ const setFormData = (data: Record<any, any>) => {
|
|||
}
|
||||
|
||||
const getDetail = async (row: Record<string, any>) => {
|
||||
console.log(row)
|
||||
|
||||
const data = await organzationDetail({
|
||||
id: row.id
|
||||
})
|
||||
console.log(data, '==')
|
||||
|
||||
setFormData(data)
|
||||
}
|
||||
|
||||
|
|
|
@ -113,8 +113,9 @@ const handleEdit = async (data: any) => {
|
|||
}
|
||||
|
||||
const handleDelete = async (id: number) => {
|
||||
const ids = [id]
|
||||
await feedback.confirm('确定要删除?')
|
||||
await organzationDelete({ id })
|
||||
await organzationDelete({ ids })
|
||||
feedback.msgSuccess('删除成功')
|
||||
getLists()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<template>
|
||||
<div class="flex flex-col items-center justify-center flex-1">
|
||||
<div class="flex flex-col gap-[6px]">
|
||||
<img :src="emptyStatusImg" style="width: 95px; height: 75px" />
|
||||
<span>您还没有分组</span>
|
||||
</div>
|
||||
<span class="mt-[6px] mb-[16px] text-[14px] text-[#999]">请新建分组后进行新建账号</span>
|
||||
<div>
|
||||
<el-button type="primary" @click="$emit('handleOrganization', 'add')">新建分组</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import emptyStatusImg from '@/assets/images/emptyStatus.png'
|
||||
|
||||
defineEmits(['handleOrganization'])
|
||||
</script>
|
||||
<style scoped></style>
|
|
@ -2,9 +2,9 @@
|
|||
<div>
|
||||
<div class="flex gap-[6px] items-center mb-[2px]">
|
||||
<el-icon color="#E6A23C"><WarningFilled /></el-icon>
|
||||
<span>此操作不可逆,确定删除该组织?</span>
|
||||
<span>此操作不可逆,确定删除【{{ name }}】组织?</span>
|
||||
</div>
|
||||
<span class="text-[14px] text-[#999] ml-[20px]">此组织下的所有成员也会被删除。</span>
|
||||
<!-- <span class="text-[14px] text-[#999] ml-[20px]">此组织下的所有成员也会被删除。</span> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -15,6 +15,12 @@ export default defineComponent({
|
|||
components: {
|
||||
WarningFilled
|
||||
},
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
setup() {
|
||||
return {
|
||||
WalletFilled
|
||||
|
|
|
@ -46,6 +46,7 @@ export interface Tree {
|
|||
id: number
|
||||
label: string
|
||||
children?: Tree[]
|
||||
name?: string
|
||||
}
|
||||
const props = defineProps({
|
||||
data: {
|
||||
|
@ -72,7 +73,7 @@ const treeRef = ref<InstanceType<typeof ElTree>>()
|
|||
const primaryAccountId = computed(() => (props.data && props.data.length > 0 ? props.data[0]?.id : 0))
|
||||
const filterNode = (value: string, data: Tree) => {
|
||||
if (!value) return true
|
||||
return data.label.includes(value)
|
||||
return data.name?.includes(value)
|
||||
}
|
||||
watch(filterText, val => {
|
||||
treeRef.value!.filter(val)
|
||||
|
|
|
@ -2,8 +2,21 @@
|
|||
<div class="flex flex-col h-full">
|
||||
<account-number :accoutnInfo="accoutnInfo" />
|
||||
<div class="flex flex-1 bg-white overflow-x-auto">
|
||||
<organization @set-selected-node="setSelectedNode" :curSelectedNode="selectedNode" @fetch-table-list="fetchTableList" />
|
||||
<account-list ref="accountListRef" :curOrganization="selectedNode" @refresh-sub-account-number="fetchSubAccountNumber" />
|
||||
<organization
|
||||
ref="organizationRef"
|
||||
@set-selected-node="setSelectedNode"
|
||||
:curSelectedNode="selectedNode"
|
||||
@fetch-table-list="fetchTableList"
|
||||
@get-organization-list="getOrganizationList"
|
||||
/>
|
||||
<!-- v-if="organzationList[0]?.children?.length > 0"-->
|
||||
<account-list
|
||||
ref="accountListRef"
|
||||
:curOrganization="selectedNode"
|
||||
@refresh-sub-account-number="fetchSubAccountNumber"
|
||||
@fetch-organization-list="fetchOrganizationList"
|
||||
/>
|
||||
<!-- <account-empty v-else /> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -12,11 +25,14 @@
|
|||
import accountNumber, { type IAccountInfo } from './modules/account-number.vue'
|
||||
import organization from './modules/organization.vue'
|
||||
import accountList from './modules/account-list.vue'
|
||||
import accountEmpty from './modules/account-empty.vue'
|
||||
import type { Tree } from './components/organization/organization-tree.vue'
|
||||
import { subAccountNumber } from '@/api/account_center/sub_account'
|
||||
import { StatusEnum } from '@/enums'
|
||||
import feedback from '@/utils/feedback'
|
||||
|
||||
const organizationRef = ref<InstanceType<typeof organization>>()
|
||||
const organzationList = ref<Tree[]>([])
|
||||
const selectedNode = ref()
|
||||
const setSelectedNode = (data: Tree) => {
|
||||
selectedNode.value = data
|
||||
|
@ -42,5 +58,13 @@ const fetchSubAccountNumber = async () => {
|
|||
} catch (error) {}
|
||||
}
|
||||
fetchSubAccountNumber()
|
||||
|
||||
const getOrganizationList = (data: Tree[]) => {
|
||||
organzationList.value = data
|
||||
}
|
||||
const fetchOrganizationList = async () => {
|
||||
organizationRef.value?.fetchOrganizationList()
|
||||
fetchTableList()
|
||||
}
|
||||
</script>
|
||||
<style scoped></style>
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<template>
|
||||
<div class="flex items-center flex-1 justify-center">
|
||||
<div class="w-[25%] gap-[20px]" v-for="(step, index) in steps" :key="step.label">
|
||||
<div class="flex flex-col items-center gap-[16px]">
|
||||
<div class="flex items-center gap-[20px]">
|
||||
<img :src="step.imagePath" style="width: 100%; height: 100%" :alt="step.label" />
|
||||
<el-icon v-if="index < steps.length - 1" :size="24" color="#999"><ArrowRightBold /></el-icon>
|
||||
</div>
|
||||
<div class="flex items-center gap-[6px]">
|
||||
<span class="font-bold text-[20px] text-primary">0{{ index + 1 }}</span>
|
||||
<span class="text-[16px]">{{ step.label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import stepOneImg from '@/assets/images/step-one.png'
|
||||
const steps = shallowRef([
|
||||
{ label: '新建组织', imagePath: stepOneImg },
|
||||
{ label: '新建分组', imagePath: stepOneImg },
|
||||
{ label: '新建账号', imagePath: stepOneImg }
|
||||
])
|
||||
</script>
|
||||
<style scoped></style>
|
|
@ -1,61 +1,67 @@
|
|||
<template>
|
||||
<div class="flex flex-col flex-1">
|
||||
<div class="h-[50px] flex items-center border-b-solid-light2 px-[20px] text-[20px] font-bold">
|
||||
{{ curOrganization.name }}
|
||||
</div>
|
||||
<div class="px-[20px] py-[16px] flex justify-between">
|
||||
<el-space>
|
||||
<el-button type="primary" :icon="Plus" :disabled="isDisabledAdd" @click="showAccountDialog">新建账号</el-button>
|
||||
<el-button type="danger" plain :icon="Delete" :disabled="isDisabled" @click="handleBatchDelete">批量删除</el-button>
|
||||
</el-space>
|
||||
<el-space>
|
||||
<el-input :placeholder="`请输入${placeholder}`" v-model="searchForm.keyword" clearable @input="handleInputChange">
|
||||
<template #prepend>
|
||||
<el-select v-model="selectKey" :placeholder="placeholder" class="w-[100px]">
|
||||
<el-option v-for="option in searchOptions" :key="option.field" :label="option.label" :value="option.field" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-select placeholder="请选择岗位名称" v-model="searchForm.postId" clearable @change="handleSelectChange">
|
||||
<el-option v-for="option in positionOptions" :key="option.id" :label="option.name" :value="option.id" />
|
||||
</el-select>
|
||||
<el-select placeholder="请选择账号状态" v-model="searchForm.isDisable" clearable @change="handleSelectChange">
|
||||
<el-option v-for="option in accountStatusOptions" :key="option.value" :label="option.label" :value="option.value" />
|
||||
</el-select>
|
||||
</el-space>
|
||||
</div>
|
||||
<ProTable ref="proTableRef" :columns="columns" :tableData="tableData" :loading="loading" :maxHeight="530">
|
||||
<template #username="{ row }">
|
||||
<template v-if="showEmptyComponent">
|
||||
<empty-content @handle-organization="handleOrganization" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="h-[50px] flex items-center border-b-solid-light2 px-[20px] text-[20px] font-bold">
|
||||
{{ curOrganization.name }}
|
||||
</div>
|
||||
<div class="px-[20px] py-[16px] flex justify-between">
|
||||
<el-space>
|
||||
<div class="w-[50px] h-[50px] bg-primary rounded-[6px] text-white flex-row-center-center">{{ row.username }}</div>
|
||||
<span>{{ row.username }}</span>
|
||||
<span
|
||||
v-if="isGroupLeader(row.groupLeader)"
|
||||
class="px-[6px] text-green border border-solid border-green rounded-[4px] text-center text-xs"
|
||||
>
|
||||
组长
|
||||
</span>
|
||||
<el-button type="primary" :icon="Plus" :disabled="isDisabledAdd" @click="showAccountDialog">新建账号</el-button>
|
||||
<el-button type="danger" plain :icon="Delete" :disabled="isDisabled" @click="handleBatchDelete">批量删除</el-button>
|
||||
</el-space>
|
||||
</template>
|
||||
<template #isDisable="{ row }">
|
||||
<el-switch
|
||||
v-model="row.isDisable"
|
||||
:active-value="isDisabledEnum.NO"
|
||||
:inactive-value="isDisabledEnum.YES"
|
||||
:before-change="() => handleStatusChange(row)"
|
||||
/>
|
||||
</template>
|
||||
<template #operation="{ row }">
|
||||
<el-button link type="primary" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button link type="primary" @click="setGroupLeader(row)">{{ btnText(row.groupLeader) }}</el-button>
|
||||
<el-button link type="primary" @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</ProTable>
|
||||
<div class="flex justify-end bg-white mt-[20px]">
|
||||
<pagination v-model="pager" @change="fetchTableList" />
|
||||
</div>
|
||||
<el-space>
|
||||
<el-input :placeholder="`请输入${placeholder}`" v-model="searchForm.keyword" clearable @input="handleInputChange">
|
||||
<template #prepend>
|
||||
<el-select v-model="selectKey" :placeholder="placeholder" class="w-[100px]">
|
||||
<el-option v-for="option in searchOptions" :key="option.field" :label="option.label" :value="option.field" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-select placeholder="请选择岗位名称" v-model="searchForm.postId" clearable @change="handleSelectChange">
|
||||
<el-option v-for="option in positionOptions" :key="option.id" :label="option.name" :value="option.id" />
|
||||
</el-select>
|
||||
<el-select placeholder="请选择账号状态" v-model="searchForm.isDisable" clearable @change="handleSelectChange">
|
||||
<el-option v-for="option in accountStatusOptions" :key="option.value" :label="option.label" :value="option.value" />
|
||||
</el-select>
|
||||
</el-space>
|
||||
</div>
|
||||
<ProTable ref="proTableRef" :columns="columns" :tableData="tableData" :loading="loading" :maxHeight="530">
|
||||
<template #username="{ row }">
|
||||
<el-space>
|
||||
<div class="w-[50px] h-[50px] bg-primary rounded-[6px] text-white flex-row-center-center">{{ row.username }}</div>
|
||||
<span>{{ row.username }}</span>
|
||||
<span
|
||||
v-if="isGroupLeader(row.groupLeader)"
|
||||
class="px-[6px] text-green border border-solid border-green rounded-[4px] text-center text-xs"
|
||||
>
|
||||
组长
|
||||
</span>
|
||||
</el-space>
|
||||
</template>
|
||||
<template #isDisable="{ row }">
|
||||
<el-switch
|
||||
v-model="row.isDisable"
|
||||
:active-value="isDisabledEnum.NO"
|
||||
:inactive-value="isDisabledEnum.YES"
|
||||
:before-change="() => handleStatusChange(row)"
|
||||
/>
|
||||
</template>
|
||||
<template #operation="{ row }">
|
||||
<el-button link type="primary" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button link type="primary" @click="setGroupLeader(row)">{{ btnText(row.groupLeader) }}</el-button>
|
||||
<el-button link type="primary" @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</ProTable>
|
||||
<div class="flex justify-end bg-white mt-[20px]">
|
||||
<pagination v-model="pager" @change="fetchTableList" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<account-dialog ref="accountDialogRef" @confirm-after="confirmAfter" />
|
||||
<edit-popup v-if="showEdit" ref="editRef" @success="fetchOrganizationList" @close="showEdit = false" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -63,8 +69,11 @@ import useHandleData from '@/hooks/useHandleData'
|
|||
import feedback from '@/utils/feedback'
|
||||
import { Plus, Delete } from '@element-plus/icons-vue'
|
||||
import accountDialog from '../components/account-list/account-dialog.vue'
|
||||
import emptyContent from '../components/account-list/empty-content.vue'
|
||||
import editPopup from '@/views/account_center/organization/edit.vue'
|
||||
|
||||
import { useDebounceFn } from '@vueuse/core'
|
||||
import { subAccountDelete, subAccountEdit, subAccountList } from '@/api/account_center/sub_account'
|
||||
import { subAccountDelete, subAccountEdit, subAccountList, subAccountUpdateStatus } from '@/api/account_center/sub_account'
|
||||
import { StatusEnum, groupLeaderEnum, isDisabledEnum } from '@/enums'
|
||||
import { omit } from 'lodash-es'
|
||||
|
||||
|
@ -74,7 +83,7 @@ const props = defineProps({
|
|||
default: () => ({})
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['refreshSubAccountNumber'])
|
||||
const emit = defineEmits(['refreshSubAccountNumber', 'fetchOrganizationList'])
|
||||
|
||||
const pager = ref({
|
||||
page: 1,
|
||||
|
@ -107,8 +116,17 @@ const columns = reactive([
|
|||
const isGroupLeader = computed(() => (groupLeader: number) => groupLeader === groupLeaderEnum.YES)
|
||||
const btnText = computed(() => (groupLeader: number) => isGroupLeader.value(groupLeader) ? '取消设为组长' : '设置组长')
|
||||
const isDisabledAdd = computed(() => props.curOrganization.status == StatusEnum.Stop)
|
||||
const showEmptyComponent = computed(() => {
|
||||
const { ancestors } = props.curOrganization
|
||||
const ancestorArray = ancestors ? ancestors.split(',') : []
|
||||
const level = ancestorArray.length - 1
|
||||
return level < 2 && !props.curOrganization?.children
|
||||
})
|
||||
const fetchTableList = async (nodeId?: number) => {
|
||||
console.log('fetchTableList')
|
||||
|
||||
loading.value = true
|
||||
tableData.value = []
|
||||
try {
|
||||
const newParams = omit(searchForm.value, ['keyword'])
|
||||
const params = {
|
||||
|
@ -122,8 +140,20 @@ const fetchTableList = async (nodeId?: number) => {
|
|||
}
|
||||
const handleStatusChange = row => {
|
||||
console.log(row)
|
||||
return new Promise(resolve => {
|
||||
resolve(true)
|
||||
const { id, isDisable } = row
|
||||
return new Promise(async resolve => {
|
||||
try {
|
||||
const params = {
|
||||
id,
|
||||
isDisable: isDisable == isDisabledEnum.YES ? isDisabledEnum.NO : isDisabledEnum.YES
|
||||
}
|
||||
const msg = isDisable == isDisabledEnum.YES ? '启用' : '停用'
|
||||
await feedback.confirm(`确定${msg}该账号?`)
|
||||
await subAccountUpdateStatus(params)
|
||||
feedback.msgSuccess(`${msg}成功`)
|
||||
resolve(true)
|
||||
fetchTableList()
|
||||
} catch (error) {}
|
||||
})
|
||||
}
|
||||
// 设置组长
|
||||
|
@ -204,6 +234,18 @@ const handleInputChange = useDebounceFn(() => {
|
|||
const handleSelectChange = () => {
|
||||
fetchTableList()
|
||||
}
|
||||
const showEdit = ref(false)
|
||||
const editRef = ref<InstanceType<typeof editPopup>>()
|
||||
const handleOrganization = async (mode: 'add' | 'edit') => {
|
||||
const { id } = props.curOrganization
|
||||
showEdit.value = true
|
||||
await nextTick()
|
||||
if (id) editRef.value?.setFormData({ pid: id })
|
||||
editRef.value?.open(mode)
|
||||
}
|
||||
const fetchOrganizationList = () => {
|
||||
emit('fetchOrganizationList', props.curOrganization)
|
||||
}
|
||||
const positionOptions = ref<any[]>([])
|
||||
|
||||
onMounted(() => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="flex flex-col w-[240px] border-r-solid-light2">
|
||||
<div class="flex flex-col w-[240px] min-w-[240px] border-r-solid-light2">
|
||||
<structure @handle-organization="handleOrganization" />
|
||||
<organization-tree
|
||||
ref="organizationTreeRef"
|
||||
|
@ -33,7 +33,7 @@ defineProps({
|
|||
default: () => ({})
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['setSelectedNode', 'fetchTableList'])
|
||||
const emit = defineEmits(['setSelectedNode', 'fetchTableList', 'getOrganizationList'])
|
||||
const data = ref<Tree[]>([])
|
||||
const loading = ref(false)
|
||||
const organizationTreeRef = ref<InstanceType<typeof organizationTree>>()
|
||||
|
@ -72,15 +72,17 @@ const handleOrganization = async (mode: 'add' | 'edit', data?: any) => {
|
|||
mode == 'edit' && editRef.value?.getDetail(data)
|
||||
}
|
||||
const handleDelete = (data?: Tree) => {
|
||||
const props = { name: data?.name }
|
||||
ElMessageBox({
|
||||
title: '温馨提示',
|
||||
showCancelButton: true,
|
||||
message: () => {
|
||||
return h(MessageBoxContent)
|
||||
return h(MessageBoxContent, props)
|
||||
},
|
||||
callback: (value: string) => {
|
||||
if (value == 'confirm') {
|
||||
organzationDelete({ id: data?.id }).then(() => {
|
||||
const ids = [data?.id]
|
||||
organzationDelete({ ids }).then(() => {
|
||||
feedback.msgSuccess('删除成功')
|
||||
fetchOrganizationList()
|
||||
})
|
||||
|
@ -89,6 +91,9 @@ const handleDelete = (data?: Tree) => {
|
|||
}
|
||||
})
|
||||
}
|
||||
defineExpose({
|
||||
fetchOrganizationList
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="flex-1 w-full chart-card">
|
||||
<card title="线索转客户统计">
|
||||
<v-charts ref="chartRef" v-loading="loading" style="height: 350px" :autoresize="true" :option="option" />
|
||||
<v-charts ref="chartRef" v-loading="loading" style="height: 350px" :autoresize="true" />
|
||||
</card>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -19,7 +19,7 @@ function createBarSeries(data, name, field) {
|
|||
}
|
||||
}
|
||||
|
||||
function createLineSeries(data, name) {
|
||||
function createLineSeries(data, name, field) {
|
||||
return {
|
||||
name,
|
||||
type: 'line',
|
||||
|
@ -28,7 +28,7 @@ function createLineSeries(data, name) {
|
|||
return value as number
|
||||
}
|
||||
},
|
||||
data: data.map(item => item.client),
|
||||
data: data.map(item => item[field]),
|
||||
yAxisIndex: 1
|
||||
}
|
||||
}
|
||||
|
@ -36,48 +36,6 @@ const loading = ref(false)
|
|||
const data = ref([])
|
||||
const xAxisData = ref([])
|
||||
|
||||
const series = [
|
||||
createBarSeries(data.value, '线索数', 'clueNumber'),
|
||||
createBarSeries(data.value, '线索转客户数', 'client'),
|
||||
createLineSeries(data.value, '线索转客户率')
|
||||
]
|
||||
|
||||
const option = ref({
|
||||
color: ['#0E66FB', '#FAC858', '#96B2D9'],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
crossStyle: {
|
||||
color: '#999'
|
||||
}
|
||||
}
|
||||
},
|
||||
toolbox: {},
|
||||
legend: {},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: xAxisData.value
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: '{value}'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: '{value}'
|
||||
}
|
||||
}
|
||||
],
|
||||
series
|
||||
})
|
||||
|
||||
const chartRef = ref()
|
||||
const fetchData = async (payload: IForm) => {
|
||||
loading.value = true
|
||||
|
@ -94,30 +52,71 @@ const fetchData = async (payload: IForm) => {
|
|||
}
|
||||
})
|
||||
xAxisData.value = result.map((item: any) => item.organizationName)
|
||||
if (series[2].data.length === 0) {
|
||||
chartRef.value.setOption({
|
||||
title: {
|
||||
text: '暂无数据',
|
||||
x: 'center',
|
||||
y: 'center'
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: [],
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
axisLine: {
|
||||
show: false
|
||||
}
|
||||
chartRef.value.setOption({
|
||||
color: ['#0E66FB', '#FAC858', '#96B2D9'],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
crossStyle: {
|
||||
color: '#999'
|
||||
}
|
||||
],
|
||||
legend: {
|
||||
show: false
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
toolbox: {},
|
||||
legend: {},
|
||||
title: {
|
||||
text: ''
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: xAxisData.value
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: '{value}'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: '{value}'
|
||||
}
|
||||
}
|
||||
],
|
||||
series: [
|
||||
createBarSeries(data.value, '线索数', 'clueNumber'),
|
||||
createBarSeries(data.value, '线索转客户数', 'client'),
|
||||
createLineSeries(data.value, '线索转客户率', 'rate')
|
||||
]
|
||||
})
|
||||
} else {
|
||||
chartRef.value.setOption({
|
||||
legend: {},
|
||||
title: {
|
||||
text: '暂无数据',
|
||||
x: 'center',
|
||||
y: 'center'
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: [],
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
axisLine: {
|
||||
show: false
|
||||
}
|
||||
}
|
||||
],
|
||||
yAxis: [],
|
||||
series: [createBarSeries([], '', ''), createBarSeries([], '', ''), createLineSeries([], '', '')]
|
||||
})
|
||||
}
|
||||
} catch (error) {}
|
||||
loading.value = false
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="flex-1 w-full chart-card">
|
||||
<card title="成交客户统计">
|
||||
<v-charts style="height: 350px" ref="chartRef" v-loading="loading" :autoresize="true" :option="option" />
|
||||
<v-charts style="height: 350px" ref="chartRef" v-loading="loading" :autoresize="true" />
|
||||
</card>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -21,38 +21,6 @@ function createBarSeries(data, name, field) {
|
|||
const chartRef = ref()
|
||||
const data = ref<any[]>([])
|
||||
const xAxisData = ref([])
|
||||
|
||||
const series = [createBarSeries(data.value, '客户数', 'clientCount'), createBarSeries(data.value, '成交客户数', 'transactionClient')]
|
||||
|
||||
const option = ref({
|
||||
color: ['#0E66FB', '#96B2D9'],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
crossStyle: {
|
||||
color: '#999'
|
||||
}
|
||||
}
|
||||
},
|
||||
toolbox: {},
|
||||
legend: {},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: xAxisData.value
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: '{value}'
|
||||
}
|
||||
}
|
||||
],
|
||||
series
|
||||
})
|
||||
const loading = ref(false)
|
||||
|
||||
const fetchData = async (payload: IForm) => {
|
||||
|
@ -68,8 +36,7 @@ const fetchData = async (payload: IForm) => {
|
|||
}
|
||||
})
|
||||
xAxisData.value = result.map((item: any) => item.organizationName)
|
||||
const allZero = data.value.every(item => item.clientCount == 0 && item.transactionClient == 0)
|
||||
if (allZero) {
|
||||
if (!result.length) {
|
||||
chartRef.value.setOption({
|
||||
title: {
|
||||
text: '暂无数据',
|
||||
|
@ -90,7 +57,41 @@ const fetchData = async (payload: IForm) => {
|
|||
],
|
||||
legend: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
series: [createBarSeries([], '', ''), createBarSeries([], '', '')]
|
||||
})
|
||||
} else {
|
||||
chartRef.value.setOption({
|
||||
color: ['#0E66FB', '#96B2D9'],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
crossStyle: {
|
||||
color: '#999'
|
||||
}
|
||||
}
|
||||
},
|
||||
toolbox: {},
|
||||
legend: {},
|
||||
title: {
|
||||
text: ''
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: xAxisData.value
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: '{value}'
|
||||
}
|
||||
}
|
||||
],
|
||||
series: [createBarSeries(data.value, '客户数', 'clientCount'), createBarSeries(data.value, '成交客户数', 'transactionClient')]
|
||||
})
|
||||
}
|
||||
} catch (error) {}
|
||||
|
|
|
@ -22,7 +22,8 @@ const loading = ref(false)
|
|||
const dataOverview = ref<any[]>([])
|
||||
const dataMap: Record<string, string> = {
|
||||
followUpRecord: '新增跟进记录(个)',
|
||||
newCustomer: '新增客户(个)',
|
||||
unclaimedQuantity: '未领取(个)',
|
||||
// newCustomer: '新增客户(个)',
|
||||
transactionClient: '成交客户(个)',
|
||||
convertingClient: '转化中客户(个)',
|
||||
exceptionPending: '异常待处理(个)',
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
default-expand-all
|
||||
:data="organizationList"
|
||||
:render-after-expand="false"
|
||||
check-strictly
|
||||
/>
|
||||
<div>
|
||||
<daterange-picker
|
||||
|
|
Loading…
Reference in New Issue