多维表格
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

295 lines
10 KiB

This file contains unexpected Bidirectional Unicode characters!

This file contains unexpected Bidirectional Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

<script setup lang="ts">
import axios from 'axios'
import { type PaginatedType, UITypes } from 'nocodb-sdk'
const props = defineProps<{
scrollLeft?: number
paginationData: PaginatedType
changePage: (page: number) => void
}>()
const emits = defineEmits(['update:paginationData'])
const { isViewDataLoading, isPaginationLoading } = storeToRefs(useViewsStore())
const isLocked = inject(IsLockedInj, ref(false))
const { changePage } = props
const vPaginationData = useVModel(props, 'paginationData', emits)
const { loadViewAggregate, updateAggregate, getAggregations, visibleFieldsComputed, displayFieldComputed } =
useViewAggregateOrThrow()
const scrollLeft = toRef(props, 'scrollLeft')
const reloadViewDataHook = inject(ReloadViewDataHookInj)
const containerElement = ref()
watch(
scrollLeft,
(value) => {
if (containerElement.value) {
containerElement.value.scrollLeft = value
}
},
{
immediate: true,
},
)
reloadViewDataHook?.on(async () => {
await loadViewAggregate()
})
const count = computed(() => vPaginationData.value?.totalRows ?? Infinity)
const page = computed({
get: () => vPaginationData?.value?.page ?? 1,
set: async (p) => {
isPaginationLoading.value = true
try {
await changePage?.(p)
isPaginationLoading.value = false
} catch (e) {
if (axios.isCancel(e)) {
return
}
isPaginationLoading.value = false
}
},
})
const size = computed({
get: () => vPaginationData.value?.pageSize ?? 25,
set: (size: number) => {
if (vPaginationData.value) {
// if there is no change in size then return
if (vPaginationData.value?.pageSize && vPaginationData.value?.pageSize === size) {
return
}
vPaginationData.value.pageSize = size
if (vPaginationData.value.totalRows && page.value * size < vPaginationData.value.totalRows) {
changePage?.(page.value)
} else {
changePage?.(1)
}
}
},
})
const renderAltOrOptlKey = () => {
return isMac() ? '⌥' : 'ALT'
}
onMounted(() => {
loadViewAggregate()
})
</script>
<template>
<div ref="containerElement" class="bg-gray-50 w-full pr-1 border-t-1 border-gray-200 overflow-x-hidden no-scrollbar flex h-9">
<div class="sticky flex items-center bg-gray-50 left-0">
<NcDropdown
:disabled="[UITypes.SpecificDBType, UITypes.ForeignKey].includes(displayFieldComputed.column?.uidt!) || isLocked"
overlay-class-name="max-h-96 relative scroll-container nc-scrollbar-thin overflow-auto"
>
<div
v-if="displayFieldComputed.field && displayFieldComputed.column?.id"
class="flex items-center overflow-x-hidden hover:bg-gray-100 cursor-pointer text-gray-500 justify-end transition-all transition-linear px-3 py-2"
:style="{
'min-width': displayFieldComputed?.width,
'max-width': displayFieldComputed?.width,
'width': displayFieldComputed?.width,
}"
>
<div class="flex relative justify-between gap-2 w-full">
<div v-if="isViewDataLoading" class="nc-pagination-skeleton flex justify-center item-center min-h-10 min-w-16 w-16">
<a-skeleton :active="true" :title="true" :paragraph="false" class="w-16 max-w-16" />
</div>
<NcTooltip v-else class="flex sticky items-center h-full">
<template #title> {{ count }} {{ count !== 1 ? $t('objects.records') : $t('objects.record') }} </template>
<span
data-testid="grid-pagination"
class="text-gray-500 text-ellipsis overflow-hidden pl-1 truncate nc-grid-row-count caption text-xs text-nowrap"
>
{{ Intl.NumberFormat('en', { notation: 'compact' }).format(count) }}
{{ count !== 1 ? $t('objects.records') : $t('objects.record') }}
</span>
</NcTooltip>
<template v-if="![UITypes.SpecificDBType, UITypes.ForeignKey].includes(displayFieldComputed.column?.uidt!)">
<div
v-if="!displayFieldComputed.field?.aggregation || displayFieldComputed.field?.aggregation === 'none'"
class="text-gray-500 opacity-0 transition group-hover:opacity-100"
>
<GeneralIcon class="text-gray-500" icon="arrowDown" />
<span class="text-[10px] font-semibold"> Summary </span>
</div>
<NcTooltip
v-else-if="displayFieldComputed.value !== undefined"
:style="{
maxWidth: `${displayFieldComputed?.width}`,
}"
>
<div style="direction: rtl" class="flex gap-2 text-nowrap truncate overflow-hidden items-center">
<span class="text-gray-600 text-[12px] font-semibold">
{{
formatAggregation(
displayFieldComputed.field.aggregation,
displayFieldComputed.value,
displayFieldComputed.column,
)
}}
</span>
<span class="text-gray-500 text-[12px] leading-4">
{{ $t(`aggregation.${displayFieldComputed.field.aggregation}`) }}
</span>
</div>
<template #title>
<div class="flex gap-2 text-nowrap overflow-hidden items-center">
<span class="text-[12px] leading-4">
{{ $t(`aggregation.${displayFieldComputed.field.aggregation}`) }}
</span>
<span class="text-[12px] font-semibold">
{{
formatAggregation(
displayFieldComputed.field.aggregation,
displayFieldComputed.value,
displayFieldComputed.column,
)
}}
</span>
</div>
</template>
</NcTooltip>
</template>
</div>
</div>
<template #overlay>
<NcMenu v-if="displayFieldComputed.field && displayFieldComputed.column?.id">
<NcMenuItem
v-for="(agg, index) in getAggregations(displayFieldComputed.column)"
:key="index"
@click="updateAggregate(displayFieldComputed.column.id, agg)"
>
<div class="flex !w-full text-[13px] text-gray-800 items-center justify-between">
{{ $t(`aggregation_type.${agg}`) }}
<GeneralIcon v-if="displayFieldComputed.field?.aggregation === agg" class="text-brand-500" icon="check" />
</div>
</NcMenuItem>
</NcMenu>
</template>
</NcDropdown>
</div>
<template v-for="({ field, width, column, value }, index) in visibleFieldsComputed" :key="index">
<NcDropdown
v-if="field && column?.id"
:disabled="[UITypes.SpecificDBType, UITypes.ForeignKey].includes(column?.uidt!) || isLocked"
overlay-class-name="max-h-96 relative scroll-container nc-scrollbar-thin overflow-auto"
>
<div
class="flex items-center overflow-x-hidden justify-end group hover:bg-gray-100 cursor-pointer text-gray-500 transition-all transition-linear px-3 py-2"
:style="{
'min-width': width,
'max-width': width,
'width': width,
}"
>
<template v-if="![UITypes.SpecificDBType, UITypes.ForeignKey].includes(column?.uidt!)">
<div
v-if="field?.aggregation === 'none' || field?.aggregation === null"
class="text-gray-500 opacity-0 transition group-hover:opacity-100"
>
<GeneralIcon class="text-gray-500" icon="arrowDown" />
<span class="text-[10px] font-semibold"> Summary </span>
</div>
<NcTooltip
v-else-if="value !== undefined"
:style="{
maxWidth: `${field?.width}px`,
}"
>
<div class="flex gap-2 truncate text-nowrap overflow-hidden items-center">
<span class="text-gray-500 text-[12px] leading-4">
{{ $t(`aggregation.${field.aggregation}`).replace('Percent ', '') }}
</span>
<span class="text-gray-600 font-semibold text-[12px]">
{{ formatAggregation(field.aggregation, value, column) }}
</span>
</div>
<template #title>
<div class="flex gap-2 text-nowrap overflow-hidden items-center">
<span class="text-[12px] leading-4">
{{ $t(`aggregation.${field.aggregation}`).replace('Percent ', '') }}
</span>
<span class="font-semibold text-[12px]">
{{ formatAggregation(field.aggregation, value, column) }}
</span>
</div>
</template>
</NcTooltip>
</template>
</div>
<template #overlay>
<NcMenu>
<NcMenuItem v-for="(agg, index) in getAggregations(column)" :key="index" @click="updateAggregate(column.id, agg)">
<div class="flex !w-full text-[13px] text-gray-800 items-center justify-between">
{{ $t(`aggregation_type.${agg}`) }}
<GeneralIcon v-if="field?.aggregation === agg" class="text-brand-500" icon="check" />
</div>
</NcMenuItem>
</NcMenu>
</template>
</NcDropdown>
</template>
<div class="!pl-8 pr-60 !w-8 h-1"></div>
<div class="fixed h-9 bg-white border-l-1 border-gray-200 px-1 flex items-center right-0">
<NcPaginationV2
v-if="count !== Infinity"
v-model:current="page"
v-model:page-size="size"
class="xs:(mr-2)"
:total="+count"
entity-name="grid"
:prev-page-tooltip="`${renderAltOrOptlKey()}+←`"
:next-page-tooltip="`${renderAltOrOptlKey()}+→`"
:first-page-tooltip="`${renderAltOrOptlKey()}+↓`"
:last-page-tooltip="`${renderAltOrOptlKey()}+↑`"
:show-size-changer="true"
/>
</div>
</div>
</template>
<style scoped lang="scss">
:deep(.nc-menu-item-inner) {
@apply w-full;
}
.nc-grid-pagination-wrapper {
.ant-pagination-item-active {
a {
@apply text-sm !text-gray-700 !hover:text-gray-800;
}
}
}
</style>
<style lang="scss"></style>