Преглед изворни кода

Merge pull request #596 from ericyuan614/master

feat: 添加表格组件及模拟数据接口,支持分页和动态列渲染
Archer пре 2 месеци
родитељ
комит
e98c66cc09

+ 39 - 2
src/api/table/index.ts

@@ -1,8 +1,45 @@
 import request from '@/axios'
 import type { TableData } from './types'
 
-export const getTableListApi = (params: any) => {
-  return request.get({ url: '/mock/example/list', params })
+interface Result {
+  list: TableData[]
+  total: number
+}
+
+// 生成模拟数据的辅助函数
+const generateMockData = (count: number): TableData[] => {
+  const stages = ['开发阶段', '测试阶段', '生产阶段', '验证阶段', '量产阶段']
+  const carTypes = ['SUV', '轿车', 'MPV', '跑车', '新能源']
+  const creators = ['张三', '李四', '王五', '赵六', '钱七']
+
+  return Array.from({ length: count }, (_, index) => ({
+    ProjectId: `PRJ${String(index + 1).padStart(3, '0')}`,
+    ProjectStage: stages[Math.floor(Math.random() * stages.length)],
+    CarType: carTypes[Math.floor(Math.random() * carTypes.length)],
+    Creator: creators[Math.floor(Math.random() * creators.length)],
+    CreateTime: new Date(Date.now() - Math.floor(Math.random() * 90) * 24 * 60 * 60 * 1000)
+      .toISOString()
+      .split('T')[0],
+    id: index + 1
+  }))
+}
+
+export const getTableListApi = (params: any): Promise<IResponse<Result>> => {
+  const mockData = generateMockData(100)
+  const { pageIndex = 1, pageSize = 10 } = params
+  const start = (pageIndex - 1) * pageSize
+  const end = start + pageSize
+
+  return Promise.resolve({
+    code: 0,
+    data: {
+      list: mockData.slice(start, end),
+      total: mockData.length
+    }
+  })
+
+  // 如果要切换到真实API,只需取消注释下面的代码
+  // return request.get({ url: '/mock/example/list', params })
 }
 
 export const getCardTableListApi = (params: any) => {

+ 7 - 8
src/api/table/types.ts

@@ -1,9 +1,8 @@
-export type TableData = {
-  id: string
-  author: string
-  title: string
-  content: string
-  importance: number
-  display_time: string
-  pageviews: number
+export interface TableData {
+  ProjectId: string
+  ProjectStage: string
+  CarType: string
+  Creator: string
+  CreateTime: string
+  id?: number
 }

+ 113 - 8
src/views/Level/Menu2.vue

@@ -1,20 +1,125 @@
-<script setup lang="ts">
-import { ElInput } from 'element-plus'
+<script setup lang="tsx">
 import { ContentWrap } from '@/components/ContentWrap'
 import { useI18n } from '@/hooks/web/useI18n'
+import { Table, TableColumn } from '@/components/Table'
+import { getTableListApi } from '@/api/table'
+import { TableData } from '@/api/table/types'
 import { ref } from 'vue'
+import { ElTag, ElPagination } from 'element-plus'
+import { BaseButton } from '@/components/Button'
+import TableColumns from './modules/TableColumn'
 
-defineOptions({
-  name: 'Menu2'
-})
+interface Params {
+  pageIndex?: number
+  pageSize?: number
+}
 
 const { t } = useI18n()
 
-const text = ref('')
+const columns: TableColumn[] = [
+  ...TableColumns,
+  {
+    field: 'action',
+    label: '操作',
+    slots: {
+      default: (data) => {
+        return (
+          <div class="flex gap-2">
+            <BaseButton type="primary" onClick={() => actionFn(data)}>
+              操作
+            </BaseButton>
+            <BaseButton type="danger" onClick={() => handleDelete(data)}>
+              删除
+            </BaseButton>
+          </div>
+        )
+      }
+    }
+  }
+]
+
+const loading = ref(true)
+
+const tableDataList = ref<TableData[]>([])
+
+// 分页相关数据
+const currentPage = ref(1)
+const pageSize = ref(10)
+const total = ref(0)
+
+const getTableList = async (params?: Params) => {
+  loading.value = true
+  const res = await getTableListApi(
+    params || {
+      pageIndex: currentPage.value,
+      pageSize: pageSize.value
+    }
+  )
+    .catch(() => {})
+    .finally(() => {
+      loading.value = false
+    })
+  if (res) {
+    tableDataList.value = res.data.list
+    total.value = res.data.total // 设置总数
+  }
+}
+
+// 分页方法
+const handleSizeChange = (val: number) => {
+  pageSize.value = val
+  getTableList()
+}
+
+const handleCurrentChange = (val: number) => {
+  currentPage.value = val
+  getTableList()
+}
+
+// 初始加载
+getTableList()
+
+const actionFn = (data: any) => {
+  console.log(data)
+}
+
+// 添加删除方法
+const handleDelete = (data: any) => {
+  console.log('删除', data)
+}
 </script>
 
 <template>
-  <ContentWrap :title="t('levelDemo.menu')">
-    <div class="flex items-center"> Menu2: <ElInput v-model="text" class="pl-20px" /> </div>
+  <ContentWrap :title="t('tableDemo.table')" :message="t('tableDemo.tableDes')">
+    <div class="table-container">
+      <Table
+        :columns="columns"
+        :data="tableDataList"
+        :loading="loading"
+        :defaultSort="{ prop: 'display_time', order: 'descending' }"
+      />
+
+      <div class="pagination-container">
+        <el-pagination
+          v-model:current-page="currentPage"
+          v-model:page-size="pageSize"
+          :page-sizes="[10, 20, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </div>
   </ContentWrap>
 </template>
+
+<style lang="less" scoped>
+.table-container {
+  .pagination-container {
+    margin-top: 20px;
+    display: flex;
+    justify-content: flex-end;
+  }
+}
+</style>

+ 26 - 0
src/views/Level/modules/TableColumn.ts

@@ -0,0 +1,26 @@
+import { ElTag } from 'element-plus'
+
+const columns = [
+  {
+    field: 'ProjectId',
+    label: '項目ID'
+  },
+  {
+    field: 'ProjectStage',
+    label: '項目階段'
+  },
+  {
+    field: 'CarType',
+    label: '車輛類型'
+  },
+  {
+    field: 'Creator',
+    label: '創建人'
+  },
+  {
+    field: 'CreateTime',
+    label: '創建時間'
+  }
+]
+
+export default columns

+ 105 - 0
src/views/ProjectMenu/ProjectMenu.vue

@@ -0,0 +1,105 @@
+<script setup lang="tsx">
+import { ContentWrap } from '@/components/ContentWrap'
+import { useI18n } from '@/hooks/web/useI18n'
+import { Table, TableColumn } from '@/components/Table'
+import { getTableListApi } from '@/api/table'
+import { TableData } from '@/api/table/types'
+import { ref, h } from 'vue'
+import { ElTag } from 'element-plus'
+import { BaseButton } from '@/components/Button'
+
+interface Params {
+  pageIndex?: number
+  pageSize?: number
+}
+
+const { t } = useI18n()
+
+const columns: TableColumn[] = [
+  {
+    field: 'title',
+    label: t('tableDemo.title')
+  },
+  {
+    field: 'author',
+    label: t('tableDemo.author')
+  },
+  {
+    field: 'display_time',
+    label: t('tableDemo.displayTime'),
+    sortable: true
+  },
+  {
+    field: 'importance',
+    label: t('tableDemo.importance'),
+    formatter: (_: Recordable, __: TableColumn, cellValue: number) => {
+      return h(
+        ElTag,
+        {
+          type: cellValue === 1 ? 'success' : cellValue === 2 ? 'warning' : 'danger'
+        },
+        () =>
+          cellValue === 1
+            ? t('tableDemo.important')
+            : cellValue === 2
+              ? t('tableDemo.good')
+              : t('tableDemo.commonly')
+      )
+    }
+  },
+  {
+    field: 'pageviews',
+    label: t('tableDemo.pageviews')
+  },
+  {
+    field: 'action',
+    label: t('tableDemo.action'),
+    slots: {
+      default: (data) => {
+        return (
+          <BaseButton type="primary" onClick={() => actionFn(data)}>
+            {t('tableDemo.action')}
+          </BaseButton>
+        )
+      }
+    }
+  }
+]
+
+const loading = ref(true)
+
+const tableDataList = ref<TableData[]>([])
+
+const getTableList = async (params?: Params) => {
+  const res = await getTableListApi(
+    params || {
+      pageIndex: 1,
+      pageSize: 10
+    }
+  )
+    .catch(() => {})
+    .finally(() => {
+      loading.value = false
+    })
+  if (res) {
+    tableDataList.value = res.data.list
+  }
+}
+
+getTableList()
+
+const actionFn = (data: any) => {
+  console.log(data)
+}
+</script>
+
+<template>
+  <ContentWrap :title="t('tableDemo.table')" :message="t('tableDemo.tableDes')">
+    <Table
+      :columns="columns"
+      :data="tableDataList"
+      :loading="loading"
+      :defaultSort="{ prop: 'display_time', order: 'descending' }"
+    />
+  </ContentWrap>
+</template>