【招生小程序】 优化# 主账号:封装下拉菜单组件

master
kaeery 2025-03-06 15:02:41 +08:00
parent 4226411775
commit 402b87b8b7
10 changed files with 416 additions and 49 deletions

View File

@ -41,3 +41,7 @@ export function convertedSuccessApi(params?: any) {
export function rankListApi(params?: any) {
return request.get({ url: '/control/top', data: params })
}
// 排名榜查看更多
export function rankMoreListApi(params?: any) {
return request.get({ url: '/control/topAll', data: params })
}

View File

@ -17,6 +17,7 @@
lineColor="#0E66FB"
@change="handleChangeTab"
></u-tabs>
<dropdownPicker ref="dropdownPickerRef" v-model="form" @refresh-page="refreshPage" />
<template v-if="loading && !data.length">
<view class="min-h-[200rpx] flex justify-center items-center">
<u-loading-icon></u-loading-icon>
@ -35,20 +36,42 @@
</template>
<script setup lang="ts">
import { onLoad } from '@dcloudio/uni-app'
import { nextTick, ref } from 'vue'
import dropdownPicker from '@/components/widgets/admin/dropdown-picker.vue'
import { useRank } from '@/hooks/useCommon'
import { watch } from 'vue'
import { IForm } from '@/components/widgets/admin/team/index.vue'
const dropdownPickerRef = ref<InstanceType<typeof dropdownPicker>>()
const form = ref<IForm>()
const { tabs, activeTab, columns, data, loading, rankStyle, handleChangeTab, fetchData } = useRank({
width: 160
})
watch(
() => activeTab.value,
(val: number) => {
console.log(val)
width: 160,
callback: () => {
fetchData(form.value)
}
)
fetchData()
})
const refreshPage = () => {
fetchData(form.value)
}
onLoad(async options => {
setFormData(options)
await nextTick()
dropdownPickerRef.value?.setDefaultValue(
decodeURIComponent(options.dropdownIndex),
decodeURIComponent(options.dateTag)
)
fetchData(form.value)
})
const setFormData = options => {
form.value = Object.keys(options).reduce((acc, key) => {
if (key == 'dropdownIndex' || key == 'dateTag') {
return acc
}
acc[key] = decodeURIComponent(options[key])
return acc
}, {})
}
defineExpose({
fetchData
})

View File

@ -68,7 +68,7 @@ export default defineComponent({
{ value: '30', label: '近30天' }
])
function initData(dropdownItem, clearValue = false) {
function initData(dropdownItem, clearValue = false, dateTag) {
const item = deepClone(dropdownItem || null)
if (clearValue === true) {
daterange.value = {
@ -81,6 +81,11 @@ export default defineComponent({
start: item.value?.start || '',
end: item.value?.end || ''
}
//
if (dateTag) {
datetag.value = dateTag
return
}
if (item.value?.start && item.value?.end) {
datetag.value = '-1'
}
@ -111,7 +116,7 @@ export default defineComponent({
if (props.dropdownItem?.prop) {
const res = { [props.dropdownItem.prop]: deepClone(daterange.value) }
emit('success', res, daterange.value, props.dropdownIndex)
emit('confirm', daterange.value)
emit('confirm', daterange.value, props.dropdownIndex, datetag.value)
} else {
console.error(`菜单项${props.dropdownItem.title}未定义prop返回内容失败`)
}
@ -133,7 +138,8 @@ export default defineComponent({
handleEndDate,
handleTagDate,
handleReset,
handleConfirm
handleConfirm,
initData
}
}
})

View File

@ -74,8 +74,11 @@ export default defineComponent({
initData(cellOptions.value)
emit('reset')
}
function clearSelect() {
initData(cellOptions.value)
}
function handleConfirm() {
emit('confirm', selectedItem.value)
emit('confirm', selectedItem.value, props.dropdownIndex)
}
watch(
() => props.dropdownItem,
@ -95,7 +98,8 @@ export default defineComponent({
showIcon,
handleSelect,
handleReset,
handleConfirm
handleConfirm,
clearSelect
}
}
})

View File

@ -0,0 +1,239 @@
<template>
<view class="bg-white">
<u-dropdown ref="uDropdownRef" menu-icon="arrow-down-fill">
<u-dropdown-item title="团队">
<view class="bg-white">
<selectDropdown
ref="teamDropdownRef"
:dropdownItem="dropdownMenuTeamList"
:dropdownIndex="dropdownMenuTeamList.dropdownIndex"
@reset="() => handleReset('team')"
@confirm="
(value, dropdownIndex) => handleConfirm('team', value, dropdownIndex)
"
/>
</view>
</u-dropdown-item>
<u-dropdown-item title="组织">
<view class="bg-white">
<selectDropdown
ref="orgDropdownRef"
:dropdownItem="dropdownMenuAllOrgaList"
:dropdownIndex="dropdownMenuAllOrgaList.dropdownIndex"
@reset="() => handleReset('organization')"
@confirm="
(value, dropdownIndex) =>
handleConfirm('organization', value, dropdownIndex)
"
/>
</view>
</u-dropdown-item>
<u-dropdown-item title="日期">
<view class="bg-white p-[20rpx]">
<dateDropdownPicker
ref="dateDropdownPickerRef"
:dropdownItem="dropdownMenuDateList"
:dropdownIndex="dropdownMenuDateList.dropdownIndex"
@reset="() => handleReset('date')"
@confirm="
(value, dropdownIndex, dateTag) =>
handleConfirm('date', value, dropdownIndex, dateTag)
"
/>
</view>
</u-dropdown-item>
</u-dropdown>
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import selectDropdown from '@/components/select-dropdown/index.vue'
import dateDropdownPicker from '@/components/date-dropdown/daterange.vue'
import { formateDate, getCurDate } from '@/utils/util'
import { PropType } from 'vue'
import { IForm } from './team/index.vue'
import { computed } from 'vue'
import { apiOrganizationByIdList, apiOrganizationList, apiOrganizationTeamList } from '@/api/admin'
const props = defineProps({
modelValue: {
type: Object as PropType<IForm>,
default: () => ({})
}
})
const emit = defineEmits(['update:modelValue', 'refreshPage', 'confirm', 'reset'])
const dateDropdownPickerRef = ref<InstanceType<typeof dateDropdownPicker>>()
const teamDropdownRef = ref<InstanceType<typeof selectDropdown>>()
const orgDropdownRef = ref<InstanceType<typeof selectDropdown>>()
const uDropdownRef = ref()
const defaultValue = ref() //
const organizationList = ref([])
const localValue = computed({
get() {
return props.modelValue
},
set(newValue) {
return emit('update:modelValue', newValue)
}
})
const dropdownMenuDateList = ref({
dropdownIndex: 3,
showQuick: true,
title: '日期范围',
type: 'daterange',
prop: 'god6',
value: { start: getCurDate('start', 'YYYY-MM-DD'), end: getCurDate('end', 'YYYY-MM-DD') }
})
const dropdownMenuTeamList = ref({
dropdownIndex: 1,
title: '下拉',
type: 'cell',
prop: 'god1',
showAll: true,
showIcon: true,
options: []
})
const dropdownMenuAllOrgaList = ref({
dropdownIndex: 2,
title: '下拉',
type: 'cell',
prop: 'god1',
showAll: true,
showIcon: true,
options: []
})
//
const handleConfirm = (type: string, item, dropdownIndex?: number, dateTag?: string) => {
switch (type) {
case 'organization':
case 'team':
//
dropdownIndex == 1
? orgDropdownRef.value.clearSelect()
: teamDropdownRef.value.clearSelect()
localValue.value = {
...localValue.value,
organizationId: item.value
}
break
case 'date':
localValue.value = {
...localValue.value,
createTimeStart: formateDate(item.start, 'start'),
createTimeEnd: formateDate(item.end, 'end')
}
break
default:
break
}
emit('refreshPage')
emit('confirm', { dropdownIndex, dateTag })
closeDropDown()
}
//
const handleReset = (type: string) => {
switch (type) {
case 'organization':
case 'team':
localValue.value = {
...localValue.value,
organizationId: defaultValue.value
}
break
case 'date':
localValue.value = {
...localValue.value,
createTimeStart: getCurDate('start'),
createTimeEnd: getCurDate('end')
}
break
default:
break
}
emit('refreshPage')
emit('reset')
closeDropDown()
}
const closeDropDown = () => {
uDropdownRef.value.close()
}
//
const fetchOrganizationList = async () => {
try {
const result = await apiOrganizationList()
organizationList.value = result ?? []
if (result.length > 0) {
localValue.value = {
...localValue.value,
organizationId: result[0].id
}
defaultValue.value = result[0].id
}
} catch (error) {}
}
//
const fetchTeamList = async () => {
try {
const result = await apiOrganizationTeamList()
dropdownMenuTeamList.value.options =
result.map(item => {
return {
label: item.name,
value: item.id
}
}) ?? []
} catch (error) {}
}
//
const fetchAllOrganizationList = async () => {
try {
const result = await apiOrganizationByIdList()
dropdownMenuAllOrgaList.value.options =
result.map(item => {
return {
label: item.name,
value: item.id
}
}) ?? []
} catch (error) {}
}
//
const setDefaultValue = (dropdownIndex: string | number[], dateTag?: string) => {
console.log(dropdownIndex)
const dataMap: Record<number, any> = {
'1': dropdownMenuTeamList,
'2': dropdownMenuAllOrgaList,
'3': dropdownMenuDateList
}
const arr = decodeURIComponent(dropdownIndex).split(',')
arr.forEach(item => {
if (
item == dropdownMenuTeamList.value.dropdownIndex ||
item == dropdownMenuAllOrgaList.value.dropdownIndex
) {
dataMap[item].value.value = Number(localValue.value.organizationId)
} else if (item == dropdownMenuDateList.value.dropdownIndex) {
dropdownMenuDateList.value.value = {
start: formateDate(localValue.value.createTimeStart, 'start', 'YYYY-MM-DD'),
end: formateDate(localValue.value.createTimeEnd, 'end', 'YYYY-MM-DD')
}
dateDropdownPickerRef.value.initData(dropdownMenuDateList.value, false, dateTag)
}
})
}
fetchTeamList()
fetchAllOrganizationList()
defineExpose({
setDefaultValue,
fetchOrganizationList,
defaultValue,
organizationList
})
</script>
<style scoped></style>

View File

@ -13,7 +13,10 @@
</template>
<template v-else>
<text class="text-[#1E40AF]">{{ parseLabel(key) }}:</text>
<text class="text-primary">{{ value }}</text>
<text class="text-primary" v-if="key === 'organizationId'">
{{ findTargetNode(value) }}
</text>
<text class="text-primary" v-else>{{ value }}</text>
</template>
</view>
</view>
@ -31,7 +34,7 @@ const formMap: Record<AdminTabEnum, any> = {
createTimeRange: '日期'
},
[AdminTabEnum.PERSONALLY]: {
postId: '组织',
postId: '岗位',
userId: '用户',
createTimeRange: '日期'
}
@ -44,6 +47,10 @@ const props = defineProps({
activeTab: {
type: Number as PropType<AdminTabEnum>,
default: AdminTabEnum.TEAM
},
organizationList: {
type: Array as PropType<any[]>,
default: () => []
}
})
const filteredForm = computed(() => {
@ -66,5 +73,30 @@ const parseLabel = computed(() => (key: string) => {
const { activeTab } = props
return formMap[activeTab][key]
})
// id
const findNodeById = (nodes: any[], id: number, key = 'id'): any | undefined => {
for (const node of nodes) {
if (node[key] === id) {
return node
}
if (node.children && node.children.length > 0) {
const foundNode = findNodeById(node.children, id)
if (foundNode) {
return foundNode
}
}
}
return undefined
}
const findTargetNode = computed(() => (id: number) => {
const nodeInfo = findNodeById(props.organizationList, id)
if (nodeInfo && nodeInfo.pid) {
const parentNode = findNodeById(props.organizationList, nodeInfo.pid, 'pid')
if (parentNode) {
return `${parentNode.name}-${nodeInfo.name}`
}
}
return nodeInfo?.name || ''
})
</script>
<style scoped></style>

View File

@ -23,7 +23,7 @@
:showText="false"
></u-line-progress>
</view>
<text>{{ item.value + '%' }}</text>
<text class="min-w-[88rpx]">{{ item.value + '%' }}</text>
</view>
</view>
</view>
@ -59,7 +59,7 @@ const fetchData = async (payload: IForm) => {
data.value = Object.keys(dataMap).map(item => {
return {
label: dataMap[item],
value: result[item] || 0
value: result[item] * 100 || 0
}
})
console.log(data.value)

View File

@ -1,6 +1,6 @@
<template>
<view class="px-[32rpx] mt-[12rpx]">
<card className="pt-2 pb-3">
<card className="pt-2 ">
<u-tabs
:list="tabs"
:scrollable="false"
@ -19,7 +19,7 @@
@change="handleChangeTab"
></u-tabs>
<template v-if="loading && !data.length">
<view class="min-h-[200rpx] flex justify-center items-center">
<view class="min-h-[400rpx] flex justify-center items-center">
<u-loading-icon></u-loading-icon>
</view>
</template>
@ -41,34 +41,51 @@
<text>查看更多</text>
</view>
</template>
<template v-else>
<w-empty />
<template v-else-if="!loading && data.length == 0">
<div class="pb-3">
<w-empty />
</div>
</template>
</card>
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import card from '../../card.vue'
import { useRank } from '@/hooks/useCommon'
const emit = defineEmits(['refresh'])
const { tabs, activeTab, columns, data, loading, rankStyle, handleChangeTab, fetchData } = useRank({
width: 120,
callback: () => {
emit('refresh')
}
})
const { tabs, columns, data, loading, rankStyle, queryParams, handleChangeTab, fetchData } =
useRank({
width: 120,
callback: () => {
emit('refresh')
}
})
const dropdownIndex = ref([])
const dateTagFlag = ref('')
const handleMore = () => {
const params = {
...queryParams.value,
dropdownIndex: encodeURIComponent(dropdownIndex.value.join(',')),
dateTag: encodeURIComponent(dateTagFlag.value)
}
const queryString = Object.keys(params)
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
.join('&')
uni.navigateTo({
url: '/bundle/pages/rank-list/index'
url: '/bundle/pages/rank-list/index?' + queryString
})
}
const setSelectedIndexArr = (indexArr: [], dateTag?: string) => {
dropdownIndex.value = indexArr
dateTagFlag.value = dateTag ?? ''
}
defineExpose({
fetchData
fetchData,
setSelectedIndexArr
})
</script>
<style scoped></style>

View File

@ -1,22 +1,38 @@
<template>
<view class="flex flex-col gap-[24rpx] mb-[20rpx]">
<view class="bg-white">
<dropdownPicker
ref="dropdownPickerRef"
v-model="form"
@refresh-page="refreshPage"
@confirm="confirm"
/>
<!-- <view class="bg-white">
<u-dropdown ref="uDropdownRef" menu-icon="arrow-down-fill">
<u-dropdown-item title="团队">
<view class="bg-white">
<selectDropdown
ref="teamDropdownRef"
:dropdownItem="dropdownMenuTeamList"
:dropdownIndex="1"
@reset="() => handleReset('team')"
@confirm="value => handleConfirm('team', value)"
@confirm="
(value, dropdownIndex) =>
handleConfirm('team', value, dropdownIndex)
"
/>
</view>
</u-dropdown-item>
<u-dropdown-item title="组织">
<view class="bg-white">
<selectDropdown
ref="orgDropdownRef"
:dropdownItem="dropdownMenuAllOrgaList"
:dropdownIndex="2"
@reset="() => handleReset('organization')"
@confirm="value => handleConfirm('organization', value)"
@confirm="
(value, dropdownIndex) =>
handleConfirm('organization', value, dropdownIndex)
"
/>
</view>
</u-dropdown-item>
@ -24,14 +40,18 @@
<view class="bg-white p-[20rpx]">
<dateDropdownPicker
:dropdownItem="dropdownMenuDateList"
:dropdownIndex="3"
@reset="() => handleReset('date')"
@confirm="value => handleConfirm('date', value)"
@confirm="
(value, dropdownIndex, dateTag) =>
handleConfirm('date', value, dropdownIndex, dateTag)
"
/>
</view>
</u-dropdown-item>
</u-dropdown>
</view>
<filter-value :form="form" :activeTab="activeTab" />
</view> -->
<filter-value :form="form" :activeTab="activeTab" :organizationList="organizationList" />
<data-overview ref="dataOverviewRef" />
<converted-overview ref="convertedOverviewRef" />
<rank ref="rankRef" @refresh="refreshData" />
@ -40,17 +60,17 @@
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { onMounted, ref, PropType } from 'vue'
import dataOverview from './components/data-overview.vue'
import convertedOverview from './components/converted-overview.vue'
import rank from './components/rank.vue'
import clueStatus from './components/clue-status.vue'
import dateDropdownPicker from '@/components/date-dropdown/daterange.vue'
import dropdownPicker from '../dropdown-picker.vue'
import selectDropdown from '@/components/select-dropdown/index.vue'
import filterValue from '../filter-value.vue'
import { apiOrganizationByIdList, apiOrganizationList, apiOrganizationTeamList } from '@/api/admin'
import { formateDate, getCurDate } from '@/utils/util'
import { PropType } from 'vue'
import { AdminTabEnum } from '@/enums'
export interface IForm {
@ -66,6 +86,9 @@ defineProps({
default: AdminTabEnum.TEAM
}
})
const dropdownPickerRef = ref<InstanceType<typeof dropdownPicker>>()
const teamDropdownRef = ref<InstanceType<typeof selectDropdown>>()
const orgDropdownRef = ref<InstanceType<typeof selectDropdown>>()
const clueStatusRef = ref<InstanceType<typeof clueStatus>>()
const rankRef = ref<InstanceType<typeof rank>>()
const convertedOverviewRef = ref<InstanceType<typeof convertedOverview>>()
@ -102,24 +125,36 @@ const dropdownMenuAllOrgaList = ref({
showIcon: true,
options: []
})
const menuIndexArr = ref<number[]>([])
const refreshPage = () => {
fetchAllData()
}
const confirm = payload => {
menuIndexArr.value = Array.from(new Set([...menuIndexArr.value, payload.dropdownIndex]))
rankRef.value?.setSelectedIndexArr(menuIndexArr.value, payload?.dateTag)
}
//
const handleConfirm = (type: string, item) => {
const handleConfirm = (type: string, item, dropdownIndex: number, dateTag?: string) => {
switch (type) {
case 'organization':
console.log(item)
case 'team':
//
dropdownIndex == 1
? orgDropdownRef.value.clearSelect()
: teamDropdownRef.value.clearSelect()
form.value.organizationId = item.value
break
case 'date':
form.value.createTimeStart = formateDate(item.start, 'start')
form.value.createTimeEnd = formateDate(item.end, 'end')
break
case 'team':
form.value.organizationId = item.value
break
default:
break
}
fetchAllData()
closeDropDown()
menuIndexArr.value = Array.from(new Set([...menuIndexArr.value, dropdownIndex]))
rankRef.value?.setSelectedIndexArr(menuIndexArr.value, dateTag)
}
//
const handleReset = (type: string) => {
@ -146,7 +181,9 @@ const refreshData = () => {
rankRef.value?.fetchData(form.value)
}
onMounted(async () => {
await fetchOrganizationList()
// await fetchOrganizationList()
await dropdownPickerRef.value?.fetchOrganizationList()
organizationList.value = dropdownPickerRef.value?.organizationList
fetchAllData()
})
const fetchAllData = () => {
@ -192,7 +229,8 @@ const fetchAllOrganizationList = async () => {
}) ?? []
} catch (error) {}
}
fetchTeamList()
fetchAllOrganizationList()
// fetchTeamList()
// fetchAllOrganizationList()
</script>
<style scoped></style>

View File

@ -51,6 +51,7 @@ export function useRank({ width, callback }: { width: number; callback?: () => v
background: styleMap[row]
}
})
const queryParams = ref()
const handleChangeTab = item => {
activeTab.value = item.id
@ -83,7 +84,9 @@ export function useRank({ width, callback }: { width: number; callback?: () => v
}
// 获取每一个岗位前5名
const fetchData = async (payload: IForm) => {
queryParams.value = payload
if (!tabs.value.length) await fetchTabs()
data.value = []
try {
loading.value = true
const newPayload = {
@ -104,6 +107,7 @@ export function useRank({ width, callback }: { width: number; callback?: () => v
tabs,
data,
loading,
queryParams,
handleChangeTab
}
}