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