重命名CubeListPager和CubeListToolbarSearch
Yann authored at 2025-07-28 22:53:20 Yann committed at 2025-07-28 23:04:14
4.52 KiB
cube-front
<script setup lang="ts">
import { inject, provide, defineAsyncComponent } from 'vue';
import type { Component } from 'vue';
import { useRoute } from 'vue-router';
import {
  ListPageHeaderKey,
  ListSearchBarKey,
  ListToolbarKey,
  ListTableContentKey,
  ListPaginationKey,
  ListPageFooterKey,
  PageSectionRegistryKey,
  SectionKeyMap,
} from '@core/composables/useSections';

import DefaultListPageHeader from '@core/views/components/ListPageHeader.vue';
import DefaultListSearchBar from '@core/views/components/ListSearchBar.vue';
import DefaultListToolbar from '@core/views/components/ListToolbar.vue';
import DefaultListTableContent from '@core/views/components/ListTableContent.vue';
import DefaultListPagination from '@core/views/components/ListPagination.vue';
import DefaultListPageFooter from '@core/views/components/ListPageFooter.vue';

interface Column {
  key: string;
  label: string;
  width?: string;
  align?: 'left' | 'center' | 'right';
  mono?: boolean;
}

interface SearchField {
  key: string;
  label: string;
  type: 'text' | 'select';
  options?: Array<{ value: string; label: string }>;
}

interface Props {
  title?: string;
  subtitle?: string;
  columns?: Column[];
  data?: Record<string, unknown>[];
  loading?: boolean;
  total?: number;
  currentPage?: number;
  pageSize?: number;
  searchFields?: SearchField[];
}

const props = withDefaults(defineProps<Props>(), {
  loading: false,
  total: 0,
  currentPage: 1,
  pageSize: 20,
});

const emit = defineEmits<{
  search: [params: Record<string, string>];
  reset: [];
  new: [];
  delete: [];
  export: [];
  refresh: [];
  'update:currentPage': [page: number];
  'update:pageSize': [size: number];
}>();

// ─── 约定式自动发现:读取当前路由对应的覆盖组件 ──────────────────
const route = useRoute();
const registry = inject(
  PageSectionRegistryKey,
  {} as Record<string, Record<string, () => Promise<{ default: unknown }>>>,
);
const pageOverrides = registry[route.path] ?? {};

for (const [name, loader] of Object.entries(pageOverrides)) {
  const key = SectionKeyMap[name];
  if (key) {
    provide(key, defineAsyncComponent(loader as () => Promise<{ default: Component }>));
  }
}

// ─── inject 回退到框架默认 ────────────────────────────────────────
const PageHeaderComp = inject(ListPageHeaderKey, DefaultListPageHeader);
const SearchBarComp = inject(ListSearchBarKey, DefaultListSearchBar);
const ToolbarComp = inject(ListToolbarKey, DefaultListToolbar);
const TableContentComp = inject(ListTableContentKey, DefaultListTableContent);
const PaginationComp = inject(ListPaginationKey, DefaultListPagination);
const PageFooterComp = inject(ListPageFooterKey, DefaultListPageFooter);
</script>

<template>
  <div class="list-page">
    <!-- 页头(在 body 外,贴顶) -->
    <slot name="header">
      <component :is="PageHeaderComp" :title="title" :subtitle="subtitle" />
    </slot>

    <div class="lp-body">
      <!-- 搜索栏 -->
      <slot name="search">
        <component
          :is="SearchBarComp"
          :fields="searchFields"
          @search="emit('search', $event)"
          @reset="emit('reset')"
        />
      </slot>

      <!-- 工具栏 -->
      <slot name="toolbar">
        <component
          :is="ToolbarComp"
          @new="emit('new')"
          @delete="emit('delete')"
          @export="emit('export')"
          @refresh="emit('refresh')"
        />
      </slot>

      <!-- 表格 -->
      <slot name="table">
        <component :is="TableContentComp" :columns="columns" :data="data" :loading="loading" />
      </slot>

      <!-- 分页 -->
      <slot name="pagination">
        <component
          :is="PaginationComp"
          :total="total"
          :current-page="currentPage"
          :page-size="pageSize"
          @update:current-page="emit('update:currentPage', $event)"
          @update:page-size="emit('update:pageSize', $event)"
        />
      </slot>

      <!-- 底部 -->
      <slot name="footer">
        <component :is="PageFooterComp" />
      </slot>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.list-page {
  height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.lp-body {
  flex: 1;
  overflow-y: auto;
  padding: 20px 24px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  background: var(--bg);

  &::-webkit-scrollbar {
    width: 6px;
  }

  &::-webkit-scrollbar-thumb {
    background: #c8d4c8;
    border-radius: 3px;
  }
}
</style>