【招生用户端】 新增# 1、排名榜:查看更多;2、封装查询组件的业务逻辑
parent
5110a2c267
commit
8271f5586d
|
@ -20,6 +20,11 @@ export function rankListApi(params?: any) {
|
|||
export function completedCustomerListApi(params?: any) {
|
||||
return request.get({ url: '/control/transactionCustomerStatistics', params })
|
||||
}
|
||||
// 排名榜查看更多
|
||||
export function rankMoreListApi(params?: any) {
|
||||
return request.get({ url: '/control/topAll', params })
|
||||
}
|
||||
|
||||
// 获取所有组织以及人员信息
|
||||
export function allUserListApi(params?: any) {
|
||||
return request.get({ url: '/organization/getAllChildOrgInfo', params })
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<template>
|
||||
<el-dialog v-model="dialogVisible" :title="parameter.title" :width="parameter.width">
|
||||
<template #header>
|
||||
<slot name="header" />
|
||||
</template>
|
||||
<slot />
|
||||
<template #footer>
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleConfirm">确认</el-button>
|
||||
<el-button type="primary" v-if="showConfirmButton" @click="handleConfirm">确认</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
@ -14,6 +17,12 @@ export interface IParams {
|
|||
width?: string | number
|
||||
data: { [key: string]: any }
|
||||
}
|
||||
defineProps({
|
||||
showConfirmButton: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['handleCancel', 'handleConfirm'])
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
|
|
|
@ -20,6 +20,8 @@ import { applyForEdit } from '@/api/finance/withdraw'
|
|||
import { useCreateModal } from './useCreateModal'
|
||||
import { toast, formatFileSize } from '@/utils/util'
|
||||
import { postLists } from '@/api/account_center/postion'
|
||||
import { organzationLists } from '@/api/account_center/organization'
|
||||
import { allUserListApi } from '@/api/workbench'
|
||||
|
||||
export interface CategoryProp {
|
||||
id: number
|
||||
|
@ -312,7 +314,7 @@ export function useUploadMoreAction() {
|
|||
previewPdf
|
||||
}
|
||||
}
|
||||
|
||||
// 岗位数据
|
||||
export function usePositionData() {
|
||||
const positionOptions = ref<any[]>([])
|
||||
const postId = ref()
|
||||
|
@ -330,3 +332,59 @@ export function usePositionData() {
|
|||
fetchPostionData
|
||||
}
|
||||
}
|
||||
// 工作台数据
|
||||
export function useWorkbench(callback?: (params: number) => void) {
|
||||
const organizationList = ref([])
|
||||
const userList = ref<any[]>([])
|
||||
const defaultProps = {
|
||||
label: 'name',
|
||||
value: 'id'
|
||||
}
|
||||
const CascaderProps = {
|
||||
label: 'name',
|
||||
value: 'id'
|
||||
}
|
||||
|
||||
const fetchOrganizationList = async () => {
|
||||
try {
|
||||
const result = await organzationLists()
|
||||
organizationList.value = result ?? []
|
||||
if (result.length > 0) callback && callback(result[0].id)
|
||||
} catch (error) {}
|
||||
}
|
||||
const fetchAllUserList = async () => {
|
||||
try {
|
||||
const result = await allUserListApi()
|
||||
const renamedData = renameFields(result)
|
||||
userList.value = renamedData
|
||||
} catch (error) {}
|
||||
}
|
||||
const renameFields = (data: any[]): any[] => {
|
||||
return data.map(item => {
|
||||
const newItem = { ...item }
|
||||
if (newItem.organizationVoList) {
|
||||
newItem.children = renameFields(newItem.organizationVoList)
|
||||
delete newItem.organizationVoList
|
||||
}
|
||||
if (newItem.userVos) {
|
||||
newItem.userVos.forEach(item => {
|
||||
item.name = item.username
|
||||
})
|
||||
newItem.children = newItem.children ? [...newItem.children, ...newItem.userVos] : newItem.userVos
|
||||
delete newItem.userVos
|
||||
}
|
||||
if (!newItem.children.length) {
|
||||
newItem.disabled = true
|
||||
}
|
||||
return newItem
|
||||
})
|
||||
}
|
||||
return {
|
||||
defaultProps,
|
||||
CascaderProps,
|
||||
organizationList,
|
||||
userList,
|
||||
fetchOrganizationList,
|
||||
fetchAllUserList
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
<template>
|
||||
<div class="flex flex-col gap-[16px] bg-white h-full">
|
||||
<div class="flex-row-between-center px-[20px] pt-[20px]">
|
||||
<span class="text-[20px] font-bold">{{ title }}</span>
|
||||
<template v-if="slotTitle">
|
||||
<slot name="title" />
|
||||
</template>
|
||||
<span v-else class="text-[20px] font-bold">{{ title }}</span>
|
||||
<slot name="right" />
|
||||
</div>
|
||||
<div class="flex-1 px-[20px] pb-[20px]">
|
||||
|
@ -17,5 +20,7 @@ defineProps({
|
|||
default: ''
|
||||
}
|
||||
})
|
||||
const slots = useSlots()
|
||||
const slotTitle = computed(() => slots?.title)
|
||||
</script>
|
||||
<style scoped></style>
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
<template>
|
||||
<ProDialog ref="proDialogRef" :showConfirmButton="false" @handle-cancel="handleCancel">
|
||||
<template #header>
|
||||
<div class="flex gap-[40px] flex-1 mb-[6px]">
|
||||
<div class="item relative" v-for="item in positionOptions" :key="item.id" @click="postId = item.id">
|
||||
<span :class="{ active: postId == item.id }">{{ item.name + '业绩排名榜' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="flex mb-[16px]">
|
||||
<el-form ref="formRef" class="mb-[-16px]" :model="queryParams" :inline="true">
|
||||
<el-form-item label="">
|
||||
<el-tree-select
|
||||
v-model="queryParams.organizationId"
|
||||
:props="defaultProps"
|
||||
default-expand-all
|
||||
:data="organizationList"
|
||||
:render-after-expand="false"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="">
|
||||
<daterange-picker
|
||||
type="datetimerange"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
isDisabledDate
|
||||
isDisabledHours
|
||||
:shortcuts="shortcuts"
|
||||
v-model:startTime="queryParams.createTimeStart"
|
||||
v-model:endTime="queryParams.createTimeEnd"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="">
|
||||
<el-cascader v-model="selectedUserId" :props="CascaderProps" :options="userList" @change="handleCascaderChange" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="resetPage">查询</el-button>
|
||||
<el-button @click="resetParams">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<ProTable ref="proTableRef" :columns="columns" :tableData="tableData" :loading="loading" :maxHeight="530"></ProTable>
|
||||
<div class="flex justify-end mt-[10px]">
|
||||
<pagination v-model="pager" @change="fetchData" layout="total, prev, pager, next, jumper" class="mb-[10px]" />
|
||||
</div>
|
||||
</ProDialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import ProDialog, { type IParams } from '@/components/ProDialog/index.vue'
|
||||
import { usePositionData, useWorkbench } from '@/hooks/useCommon'
|
||||
import { rankMoreListApi } from '@/api/workbench'
|
||||
import { getCurDate, shortcuts } from '@/utils/util'
|
||||
|
||||
const { positionOptions, postId, fetchPostionData } = usePositionData()
|
||||
|
||||
const pager = ref({
|
||||
page: 1,
|
||||
size: 10,
|
||||
count: 0
|
||||
})
|
||||
const proDialogRef = ref<InstanceType<typeof ProDialog>>()
|
||||
const loading = ref(false)
|
||||
const proTableRef = ref()
|
||||
const tableData = ref<any[]>([])
|
||||
const columns = reactive([
|
||||
{ prop: 'rank', label: '排名' },
|
||||
{ prop: 'username', label: '账号名称' },
|
||||
{ prop: 'clueCount', label: '总数' }
|
||||
])
|
||||
const queryParams = ref()
|
||||
const initialVal = ref()
|
||||
const { defaultProps, CascaderProps, organizationList, userList, fetchOrganizationList, fetchAllUserList } = useWorkbench(id => {
|
||||
initialVal.value = id
|
||||
})
|
||||
const selectedUserId = ref([])
|
||||
|
||||
const openDialog = async (params: IParams) => {
|
||||
queryParams.value = params.data
|
||||
await fetchPostionData()
|
||||
fetchOrganizationList()
|
||||
fetchAllUserList()
|
||||
fetchData()
|
||||
proDialogRef.value?.openDialog(params)
|
||||
}
|
||||
const fetchData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const newParams = {
|
||||
...queryParams.value,
|
||||
post: postId.value ?? queryParams.value.post
|
||||
}
|
||||
const result = await rankMoreListApi(newParams)
|
||||
tableData.value = result.lists ?? []
|
||||
pager.value = {
|
||||
page: result.pageNo,
|
||||
size: result.pageSize,
|
||||
count: result.count
|
||||
}
|
||||
} catch (error) {}
|
||||
loading.value = false
|
||||
}
|
||||
const handleCancel = (callback: () => void) => {
|
||||
callback()
|
||||
}
|
||||
watch(
|
||||
() => postId.value,
|
||||
(newVal, oldVal) => {
|
||||
if (newVal !== oldVal) {
|
||||
fetchData()
|
||||
}
|
||||
}
|
||||
)
|
||||
const resetPage = () => {
|
||||
fetchData()
|
||||
}
|
||||
const resetParams = () => {
|
||||
queryParams.value = {
|
||||
organizationId: initialVal.value,
|
||||
createTimeStart: getCurDate('start').toString(),
|
||||
createTimeEnd: getCurDate('end').toString(),
|
||||
userId: ''
|
||||
}
|
||||
selectedUserId.value = []
|
||||
fetchData()
|
||||
}
|
||||
const handleCascaderChange = value => {
|
||||
const lastVal = value[value.length - 1]
|
||||
queryParams.value = {
|
||||
...queryParams.value,
|
||||
userId: lastVal.toString()
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
openDialog
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.item {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
> span {
|
||||
&.active {
|
||||
position: relative;
|
||||
color: var(--el-color-primary);
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -10px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 46px;
|
||||
height: 3px;
|
||||
border-radius: 3px;
|
||||
background-color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
.active {
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,7 +1,17 @@
|
|||
<template>
|
||||
<div class="rank flex-1">
|
||||
<card title="TOP5">
|
||||
<template #title>
|
||||
<div class="flex gap-[40px] title flex-1 mb-[6px]">
|
||||
<div class="item relative" v-for="item in positionOptions" :key="item.id" @click="postId = item.id">
|
||||
<span :class="{ active: postId == item.id }">{{ item.name + 'TOP5' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #right>
|
||||
<span class="text-primary cursor-pointer" @click="handleMore">查看更多</span>
|
||||
</template>
|
||||
<!-- <template #right>
|
||||
<div class="positions">
|
||||
<span
|
||||
class="default"
|
||||
|
@ -13,24 +23,26 @@
|
|||
{{ item.name }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="tableData.length > 0">
|
||||
<el-table :data="tableData" v-loading="loading">
|
||||
</template> -->
|
||||
<template v-if="!loading && tableData.length > 0">
|
||||
<el-table :data="tableData" v-loading="loading" style="min-height: 300px">
|
||||
<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>
|
||||
<template v-if="!loading && tableData.length == 0">
|
||||
<el-empty description="暂无数据" />
|
||||
</template>
|
||||
</card>
|
||||
</div>
|
||||
<rankListDialog ref="rankListDialogRef" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { rankListApi } from '@/api/workbench'
|
||||
import card from './card.vue'
|
||||
import rankListDialog from './rank-list-dialog.vue'
|
||||
import type { IForm } from '../index.vue'
|
||||
import { usePositionData } from '@/hooks/useCommon'
|
||||
|
||||
|
@ -38,8 +50,10 @@ const { positionOptions, postId, fetchPostionData } = usePositionData()
|
|||
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
||||
const rankListDialogRef = ref<InstanceType<typeof rankListDialog>>()
|
||||
const tableData = ref([])
|
||||
const loading = ref(false)
|
||||
const queryParams = ref()
|
||||
const fetchData = async (payload: IForm) => {
|
||||
if (!positionOptions.value.length) await fetchPostionData()
|
||||
if (tableData.value.length > 0) tableData.value = []
|
||||
|
@ -50,12 +64,18 @@ const fetchData = async (payload: IForm) => {
|
|||
post: postId.value
|
||||
}
|
||||
const result = await rankListApi(newPayload)
|
||||
console.log(result)
|
||||
|
||||
tableData.value = result ?? []
|
||||
queryParams.value = newPayload // 记录查询参数
|
||||
} catch (error) {}
|
||||
loading.value = false
|
||||
}
|
||||
const handleMore = () => {
|
||||
rankListDialogRef.value?.openDialog({
|
||||
title: '排行榜',
|
||||
width: 1100,
|
||||
data: { ...queryParams.value }
|
||||
})
|
||||
}
|
||||
watch(
|
||||
() => postId.value,
|
||||
(newVal, oldVal) => {
|
||||
|
@ -71,6 +91,29 @@ defineExpose({
|
|||
<style scoped lang="scss">
|
||||
.rank {
|
||||
min-height: 350px;
|
||||
.item {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
> span {
|
||||
&.active {
|
||||
position: relative;
|
||||
color: var(--el-color-primary);
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -10px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 46px;
|
||||
height: 3px;
|
||||
border-radius: 3px;
|
||||
background-color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
.active {
|
||||
}
|
||||
}
|
||||
.positions {
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
|
|
|
@ -31,20 +31,11 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { organzationLists } from '@/api/account_center/organization'
|
||||
import { shortcuts } from '@/utils/util'
|
||||
import type { PropType } from 'vue'
|
||||
import type { IForm } from '../index.vue'
|
||||
import { allUserListApi } from '@/api/workbench'
|
||||
import { useWorkbench } from '@/hooks/useCommon'
|
||||
import { shortcuts } from '@/utils/util'
|
||||
|
||||
const defaultProps = {
|
||||
label: 'name',
|
||||
value: 'id'
|
||||
}
|
||||
const CascaderProps = {
|
||||
label: 'name',
|
||||
value: 'id'
|
||||
}
|
||||
const props = defineProps({
|
||||
queryParams: {
|
||||
type: Object as PropType<IForm>,
|
||||
|
@ -65,6 +56,14 @@ const localValue = computed({
|
|||
emit('update:queryParams', newValue)
|
||||
}
|
||||
})
|
||||
const { defaultProps, CascaderProps, organizationList, userList, fetchOrganizationList, fetchAllUserList } = useWorkbench(id => {
|
||||
localValue.value = {
|
||||
...localValue.value,
|
||||
organizationId: id
|
||||
}
|
||||
emit('fectAllData', id)
|
||||
})
|
||||
|
||||
const selectedUserId = ref([])
|
||||
|
||||
const resetParams = () => {
|
||||
|
@ -74,48 +73,6 @@ const resetParams = () => {
|
|||
const resetPage = () => {
|
||||
emit('resetPage')
|
||||
}
|
||||
const organizationList = ref([])
|
||||
const userList = ref<any[]>([])
|
||||
const fetchOrganizationList = async () => {
|
||||
try {
|
||||
const result = await organzationLists()
|
||||
organizationList.value = result ?? []
|
||||
if (result.length > 0) {
|
||||
localValue.value = {
|
||||
...localValue.value,
|
||||
organizationId: result[0].id
|
||||
}
|
||||
emit('fectAllData', result[0].id)
|
||||
}
|
||||
} catch (error) {}
|
||||
}
|
||||
const fetchAllUserList = async () => {
|
||||
try {
|
||||
const result = await allUserListApi()
|
||||
const renamedData = renameFields(result)
|
||||
userList.value = renamedData
|
||||
} catch (error) {}
|
||||
}
|
||||
const renameFields = (data: any[]): any[] => {
|
||||
return data.map(item => {
|
||||
const newItem = { ...item }
|
||||
if (newItem.organizationVoList) {
|
||||
newItem.children = renameFields(newItem.organizationVoList)
|
||||
delete newItem.organizationVoList
|
||||
}
|
||||
if (newItem.userVos) {
|
||||
newItem.userVos.forEach(item => {
|
||||
item.name = item.username
|
||||
})
|
||||
newItem.children = newItem.children ? [...newItem.children, ...newItem.userVos] : newItem.userVos
|
||||
delete newItem.userVos
|
||||
}
|
||||
if (!newItem.children.length) {
|
||||
newItem.disabled = true
|
||||
}
|
||||
return newItem
|
||||
})
|
||||
}
|
||||
const handleCascaderChange = value => {
|
||||
const lastVal = value[value.length - 1]
|
||||
localValue.value = {
|
||||
|
|
Loading…
Reference in New Issue