多维表格
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.
 
 
 
 
 
 

373 lines
9.2 KiB

<script lang="ts" setup>
import type { ColumnType, GridType } from 'nocodb-sdk'
import InfiniteTable from './InfiniteTable.vue'
import Table from './Table.vue'
import GroupBy from './GroupBy.vue'
const meta = inject(MetaInj, ref())
const view = inject(ActiveViewInj, ref())
const reloadViewDataHook = inject(ReloadViewDataHookInj, createEventHook())
const router = useRouter()
const route = router.currentRoute
const { xWhere, eventBus } = useSmartsheetStoreOrThrow()
const { t } = useI18n()
const { isFeatureEnabled } = useBetaFeatureToggle()
const bulkUpdateDlg = ref(false)
const routeQuery = computed(() => route.value.query as Record<string, string>)
const expandedFormDlg = ref(false)
const expandedFormRow = ref<Row>()
const expandedFormRowState = ref<Record<string, any>>()
const reloadVisibleDataHook = createEventHook()
provide(ReloadVisibleDataHookInj, reloadVisibleDataHook)
const tableRef = ref<typeof InfiniteTable>()
useProvideViewAggregate(view, meta, xWhere)
const {
loadData,
selectedRows,
updateOrSaveRow,
addEmptyRow: _addEmptyRow,
deleteRow,
deleteSelectedRows,
cachedRows,
clearCache,
removeRowIfNew,
navigateToSiblingRow,
deleteRangeOfRows,
bulkUpdateRows,
bulkUpsertRows,
syncCount,
totalRows,
syncVisibleData,
optimisedQuery,
isLastRow,
isFirstRow,
chunkStates,
clearInvalidRows,
isRowSortRequiredRows,
applySorting,
isBulkOperationInProgress,
} = useGridViewData(meta, view, xWhere, reloadVisibleDataHook)
const rowHeight = computed(() => {
if ((view.value?.view as GridType)?.row_height !== undefined) {
switch ((view.value?.view as GridType)?.row_height) {
case 0:
return 1
case 1:
return 2
case 2:
return 4
case 3:
return 6
default:
return 1
}
}
})
provide(IsFormInj, ref(false))
provide(IsGalleryInj, ref(false))
provide(IsGridInj, ref(true))
provide(IsCalendarInj, ref(false))
provide(RowHeightInj, rowHeight)
const isPublic = inject(IsPublicInj, ref(false))
provide(ReloadRowDataHookInj, reloadViewDataHook)
const skipRowRemovalOnCancel = ref(false)
function expandForm(row: Row, state?: Record<string, any>, fromToolbar = false) {
const rowId = extractPkFromRow(row.row, meta.value?.columns as ColumnType[])
expandedFormRowState.value = state
if (rowId && !isPublic.value) {
expandedFormRow.value = undefined
router.push({
query: {
...routeQuery.value,
rowId,
},
})
} else {
expandedFormRow.value = row
expandedFormDlg.value = true
skipRowRemovalOnCancel.value = !fromToolbar
}
}
const exposeOpenColumnCreate = (data: any) => {
tableRef.value?.openColumnCreate(data)
}
defineExpose({
loadData,
openColumnCreate: exposeOpenColumnCreate,
})
const expandedFormOnRowIdDlg = computed({
get() {
return !!routeQuery.value.rowId
},
set(val) {
if (!val)
router.push({
query: {
...routeQuery.value,
rowId: undefined,
},
})
},
})
const addRowExpandOnClose = (row: Row) => {
if (!skipRowRemovalOnCancel.value) {
eventBus.emit(SmartsheetStoreEvents.CLEAR_NEW_ROW, row)
}
}
const toggleOptimisedQuery = () => {
if (optimisedQuery.value) {
optimisedQuery.value = false
message.info(t('msg.optimizedQueryDisabled'))
} else {
optimisedQuery.value = true
message.info(t('msg.optimizedQueryEnabled'))
}
}
const {
rootGroup,
groupBy,
isGroupBy,
loadGroups,
loadGroupData,
loadGroupPage,
groupWrapperChangePage,
redistributeRows,
loadGroupAggregation,
} = useViewGroupByOrThrow()
const sidebarStore = useSidebarStore()
const { windowSize, leftSidebarWidth } = toRefs(sidebarStore)
const viewWidth = ref(0)
eventBus.on((event) => {
if (event === SmartsheetStoreEvents.GROUP_BY_RELOAD || event === SmartsheetStoreEvents.DATA_RELOAD) {
reloadViewDataHook?.trigger()
}
})
const goToNextRow = () => {
navigateToSiblingRow(NavigateDir.NEXT)
}
const goToPreviousRow = () => {
navigateToSiblingRow(NavigateDir.PREV)
}
const updateViewWidth = () => {
if (isPublic.value) {
viewWidth.value = windowSize.value
return
}
viewWidth.value = windowSize.value - leftSidebarWidth.value
}
const baseColor = computed(() => {
switch (groupBy.value.length) {
case 1:
return '#F9F9FA'
case 2:
return '#F4F4F5'
case 3:
return '#E7E7E9'
default:
return '#F9F9FA'
}
})
const updateRowCommentCount = (count: number) => {
if (!routeQuery.value.rowId) return
const currentRowIndex = Array.from(cachedRows.value.values()).find(
(row) => extractPkFromRow(row.row, meta.value!.columns!) === routeQuery.value.rowId,
)?.rowMeta.rowIndex
if (currentRowIndex === undefined) return
const currentRow = cachedRows.value.get(currentRowIndex)
if (!currentRow) return
currentRow.rowMeta.commentCount = count
syncVisibleData?.()
}
watch([windowSize, leftSidebarWidth], updateViewWidth)
onMounted(() => {
updateViewWidth()
})
const {
selectedAllRecords: pSelectedAllRecords,
formattedData: pData,
paginationData: pPaginationData,
loadData: pLoadData,
changePage: pChangePage,
addEmptyRow: pAddEmptyRow,
deleteRow: pDeleteRow,
updateOrSaveRow: pUpdateOrSaveRow,
deleteSelectedRows: pDeleteSelectedRows,
deleteRangeOfRows: pDeleteRangeOfRows,
bulkUpdateRows: pBulkUpdateRows,
removeRowIfNew: pRemoveRowIfNew,
} = useViewData(meta, view, xWhere)
</script>
<template>
<div
class="relative flex flex-col h-full min-h-0 w-full nc-grid-wrapper"
data-testid="nc-grid-wrapper"
:style="`background-color: ${isGroupBy ? `${baseColor}` : 'var(--nc-grid-bg)'};`"
>
<Table
v-if="!isGroupBy && !isFeatureEnabled(FEATURE_FLAG.INFINITE_SCROLLING)"
ref="tableRef"
v-model:selected-all-records="pSelectedAllRecords"
:data="pData"
:pagination-data="pPaginationData"
:load-data="pLoadData"
:change-page="pChangePage"
:call-add-empty-row="pAddEmptyRow"
:delete-row="pDeleteRow"
:update-or-save-row="pUpdateOrSaveRow"
:delete-selected-rows="pDeleteSelectedRows"
:delete-range-of-rows="pDeleteRangeOfRows"
:bulk-update-rows="pBulkUpdateRows"
:expand-form="expandForm"
:remove-row-if-new="pRemoveRowIfNew"
:row-height="rowHeight"
@toggle-optimised-query="toggleOptimisedQuery"
@bulk-update-dlg="bulkUpdateDlg = true"
/>
<InfiniteTable
v-else-if="!isGroupBy"
ref="tableRef"
:load-data="loadData"
:call-add-empty-row="_addEmptyRow"
:delete-row="deleteRow"
:update-or-save-row="updateOrSaveRow"
:delete-selected-rows="deleteSelectedRows"
:delete-range-of-rows="deleteRangeOfRows"
:apply-sorting="applySorting"
:bulk-update-rows="bulkUpdateRows"
:bulk-upsert-rows="bulkUpsertRows"
:clear-cache="clearCache"
:clear-invalid-rows="clearInvalidRows"
:data="cachedRows"
:total-rows="totalRows"
:sync-count="syncCount"
:chunk-states="chunkStates"
:expand-form="expandForm"
:remove-row-if-new="removeRowIfNew"
:row-height-enum="rowHeight"
:selected-rows="selectedRows"
:row-sort-required-rows="isRowSortRequiredRows"
:is-bulk-operation-in-progress="isBulkOperationInProgress"
@toggle-optimised-query="toggleOptimisedQuery"
@bulk-update-dlg="bulkUpdateDlg = true"
/>
<GroupBy
v-else
:group="rootGroup"
:load-groups="loadGroups"
:load-group-data="loadGroupData"
:load-group-page="loadGroupPage"
:group-wrapper-change-page="groupWrapperChangePage"
:row-height="rowHeight"
:load-group-aggregation="loadGroupAggregation"
:max-depth="groupBy.length"
:redistribute-rows="redistributeRows"
:view-width="viewWidth"
/>
<Suspense v-if="!isGroupBy">
<LazySmartsheetExpandedForm
v-if="expandedFormRow && expandedFormDlg"
v-model="expandedFormDlg"
:load-row="!isPublic"
:row="expandedFormRow"
:state="expandedFormRowState"
:meta="meta"
:view="view"
@update:model-value="addRowExpandOnClose(expandedFormRow)"
/>
</Suspense>
<SmartsheetExpandedForm
v-if="expandedFormOnRowIdDlg && meta?.id && !isGroupBy"
v-model="expandedFormOnRowIdDlg"
:row="expandedFormRow ?? { row: {}, oldRow: {}, rowMeta: {} }"
:meta="meta"
:load-row="!isPublic"
:state="expandedFormRowState"
:row-id="routeQuery.rowId"
:view="view"
show-next-prev-icons
:first-row="isFirstRow"
:last-row="isLastRow"
:expand-form="expandForm"
@next="goToNextRow()"
@prev="goToPreviousRow()"
@update-row-comment-count="updateRowCommentCount"
/>
<Suspense>
<LazyDlgBulkUpdate
v-if="bulkUpdateDlg"
v-model="bulkUpdateDlg"
:meta="meta"
:view="view"
:bulk-update-rows="bulkUpdateRows"
:rows="selectedRows"
/>
</Suspense>
</div>
</template>
<style lang="scss">
.nc-grid-pagination-wrapper .ant-dropdown-button {
> .ant-btn {
@apply !p-0 !rounded-l-lg hover:border-gray-300;
}
> .ant-dropdown-trigger {
@apply !rounded-r-lg;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
@apply !rounded-lg;
}
</style>