Gi Admin Pro

repository·master·Indexed 41 days ago

https://github.com/lin-97/gi-demo

A free mid-to-back-office admin template built with Vue 3, Vite, and TypeScript. It features rich theme configurations, dark mode, and strict code standards. The project includes a production mock server via vite-plugin-mock and uses @antfu/eslint-config for linting.

Tokens
24.6K
Snippets
105
Records
118
Agent score
51%

What's inside Gi Admin Pro

  1. Understand Gi Admin Pro naming conventions

    master

    Gi Admin Pro follows specific naming conventions for components and styles to ensure consistency and ease of use:

    Global Component Prefix

    All global components use the Gi prefix (e.g., GiTable, GiForm, GiPageLayout). This prefix is used to distinguish global components from local ones and supports on-demand loading.

    Component Naming (PascalCase)

    .vue filenames and component usage in templates follow PascalCase (e.g., MyComponent.vue). This follows the Vue style guide and improves searchability compared to kebab-case.

    CSS Class Naming (kebab-case)

    CSS class names use kebab-case (e.g., .my-class-name) to align with industry standards.

  2. Follow Vue component and naming conventions

    master

    To maintain code quality and consistency in the project, follow these naming and structural guidelines:

    Component Files

    • Global Components: Use PascalCase (e.g., GiForm.vue, GiTable.vue).
    • Local Components: Use PascalCase (e.g., AddModal.vue, EditDrawer.vue).
    • Folder Names: Use lowercase with hyphens (kebab-case) for long names (e.g., user-detail/index.vue).

    Vue Script Setup Patterns

    • Computed Properties: Prefer concise one-liners when possible.
    • Form Handling: Use reactive for forms. For complex forms, use a factory function (e.g., getInitForm) to facilitate resetting.
    • Store/Hook Naming: Follow the pattern const appStore = useAppStore() and const { loading } = useLoading().

    CSS Naming

    • Use lowercase with hyphens (kebab-case) or the BEM (Block Element Modifier) convention.
    • Use global CSS variables for spacing, such as var(--margin) and var(--padding).
  3. Implement efficient coding patterns in Vue

    master

    Use these patterns to improve readability and maintainability:

    • Ternary Operators: Use instead of if/else for simple assignments.
    • Array Includes: Use [1, 2, 3].includes(type) instead of multiple || checks.
    • Arrow Functions: Use for concise function definitions.
    • Object Mapping: Replace if/else if chains with object lookups (e.g., const message = messageMap[status]).
    • Object Parameters: When a function has more than two arguments, pass them as a single object to improve extensibility and readability.
    // Instead of multiple arguments
    function createUser({ name, phone, age }: { name: string, phone: string, age: number }) {
      console.log('姓名', name)
    }
    
    createUser({ name: '张三', phone: '178****2828', age: 20 })
  4. Install and run Gi Admin Pro

    master

    To get started with the Gi Admin Pro template, install the dependencies using npm and then start the development server.

    Installation

    npm install

    Development

    To run the project in development mode:

    npm run dev

    Production Build

    To build the project for production:

    npm run build
    npm install
    npm run dev
    npm run build
  5. Handle API calls with different requirements

    master

    Depending on whether you need loading states or error handling, use one of the following three patterns for asynchronous API calls (assuming getUserListApi is an Axios-based function):

    1. Basic: No loading, no error handling (relies on global interceptors).
    2. Full: Includes loading state and try/catch/finally for error handling and UI feedback.
    3. Loading Only: Includes loading state but omits explicit catch blocks (useful if errors are handled globally).
    // Pattern 2: Loading + Error Handling
    const loading = ref(false)
    const userList = ref<UserItem[]>([])
    
    const getUserList = async () => {
      try {
        loading.value = true
        const res = await getUserListApi()
        userList.value = res.data
      } catch (error) {
        // Error handling logic
      } finally {
        loading.value = false
      }
    }
  6. Encapsulate and expose Modal or Drawer components

    master

    When building reusable Modal or Drawer components, use defineExpose to allow parent components to trigger actions like add or edit via template refs.

    <template>
      <a-modal v-model:visible="visible" :title="title" @ok="confirm">
        <!-- Content -->
      </a-modal>
    </template>
    
    <script setup lang="ts">
    import { ref, computed } from 'vue'
    
    const visible = ref(false)
    const detailId = ref('')
    const isEdit = computed(() => !!detailId.value)
    const title = computed(() => (isEdit.value ? '编辑' : '新增'))
    
    const add = () => {
      detailId.value = ''
      visible.value = true
    }
    
    const edit = (id: string) => {
      detailId.value = id
      visible.value = true
    }
    
    // Expose methods to parent
    defineExpose({ add, edit })
    
    const confirm = () => { /* ... */ }
    </script>
    
    <!-- Usage in Parent -->
    <template>
      <EditModal ref="EditModalRef"></EditModal>
    </template>
    
    <script setup lang="ts">
    import { ref } from 'vue'
    import EditModal from './EditModal.vue'
    
    const EditModalRef = ref<InstanceType<typeof EditModal>>()
    
    const onAdd = () => EditModalRef.value?.add()
    const onEdit = (id: string) => EditModalRef.value?.edit(id)
    </script>
  7. Dynamic visibility and disabled states in GiForm

    master

    Form items can have their visibility (hide) or enabled state (disabled) controlled dynamically based on the current form model values. You can pass either a boolean or a function that receives the current form model as an argument.

    interface MyFormData {
      isSpecial: boolean;
      extraInfo: string;
    }
    
    const columns: FormColumnItem<MyFormData>[] = [
      {
        field: 'isSpecial',
        type: 'switch',
        label: 'Enable Special Mode'
      },
      {
        field: 'extraInfo',
        type: 'input',
        label: 'Special Info',
        // Only show this field if isSpecial is true
        hide: (model) => !model.isSpecial,
        // Disable this field if isSpecial is false
        disabled: (model) => !model.isSpecial
      }
    ];
  8. Use slots in GiForm columns

    master

    You can customize the rendering of specific parts of a form item using the slots property in a FormColumnItem. This allows you to inject custom VNodes into specific sub-components (like the prefix of an input or the options of a select).

    // Example: Customizing a Select component's label and option rendering
    const columns: FormColumnItem[] = [
      {
        field: 'category',
        type: 'select',
        slots: {
          label: ({ data }) => h('span', { style: 'color: red' }, data.label),
          option: ({ data }) => h('div', data.label)
        }
      }
    ];
  9. How cross-page selection works in useTable

    master

    By default, useTable only tracks selection for the current visible page. If you enable crossPageSelect: true in the useTable options, the hook will maintain a persistent list of selected keys across different pages.

    • When crossPageSelect is false (default): selectedKeys is overwritten by the keys of the current page whenever a selection event occurs.
    • When crossPageSelect is true: The hook merges the new selection with the existing selectedKeys, ensuring that keys from previously visited pages are preserved unless they are explicitly deselected.
  10. Format backend menu data into Vue Router configurations

    master

    The routing system converts backend UserRouteItem objects into RouteRecordRaw objects. This process involves:

    1. Sorting: Menus are sorted based on their sort field (ascending order).
    2. Component Resolution: String-based component identifiers (e.g., 'Layout' or 'system/user/index') are resolved into actual Vue components or dynamic import functions.
    3. Metadata Mapping: Backend properties are mapped to the Vue Router meta object:
      • hidden: Whether to hide the item in the menu.
      • keepAlive: Whether to cache the route.
      • title: The display title.
      • icon: The icon identifier.
      • affix: Whether to fix the tab in the tab bar.
      • breadcrumb: Whether to show in breadcrumbs.
      • showInTabs: Whether to show in the tabs bar.
      • activeMenu: The menu item to activate.
      • alwaysShow: Whether to always show the parent menu.

    Note: The component resolution uses a cached map of the src/views directory to ensure efficient lookups.

  11. Configure ESLint with @antfu/eslint-config

    master

    This project uses @antfu/eslint-config for linting. The configuration is exported as a default function call that accepts multiple configuration objects. You can enable core features like vue and typescript via the first configuration object and define specific rules or file patterns in subsequent objects.

    Key configuration options in the primary object:

    • vue: Boolean to enable Vue linting support.
    • typescript: Boolean to enable TypeScript linting support.
    • ignores: Array of file patterns to exclude from linting (e.g., README.md).
    import antfu from '@antfu/eslint-config'
    
    export default antfu(
      {
        vue: true,
        typescript: true,
        ignores: [
          'README.md',
          'src/types/shims-vue.d.ts'
        ]
      },
      // ... additional config objects
    )