refactor: 将记分板功能模块化为可复用组件
- 创建 app/modules/scoreboard 模块目录
- 添加配置常量 (EVENT_CATEGORIES, TEAM_GROUPS, EVENT_TYPES)
- 添加 API 工具函数 (fetchEvents, fetchTeams, fetchResults 等)
- 添加可复用组件 (ModuleLayout, StatCard, DataTable)
- 添加模块导出文件 (mod.ts)
- 添加模块使用文档 (README.md)
- 更新首页使用模块 API 函数
后续可通过 import { xxx } from '~/modules/scoreboard' 导入使用
This commit is contained in:
parent
22f073d8e7
commit
94dbd0d34c
51
app/modules/scoreboard/DataTable.vue
Normal file
51
app/modules/scoreboard/DataTable.vue
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<template>
|
||||||
|
<el-table :data="data" border stripe class="scoreboard-table">
|
||||||
|
<el-table-column
|
||||||
|
v-for="column in columns"
|
||||||
|
:key="column.prop"
|
||||||
|
:prop="column.prop"
|
||||||
|
:label="column.label"
|
||||||
|
:width="column.width"
|
||||||
|
:class-name="column.className"
|
||||||
|
:sortable="column.sortable"
|
||||||
|
>
|
||||||
|
<template v-if="column.slot" #default="{ row }">
|
||||||
|
<slot :name="column.slot" :row="row">
|
||||||
|
{{ row[column.prop] }}
|
||||||
|
</slot>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
interface Column {
|
||||||
|
prop: string
|
||||||
|
label: string
|
||||||
|
width?: number | string
|
||||||
|
className?: string
|
||||||
|
sortable?: boolean
|
||||||
|
slot?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
data: any[]
|
||||||
|
columns: Column[]
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps<Props>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.scoreboard-table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.scoreboard-table :deep(.col-group),
|
||||||
|
.scoreboard-table :deep(.col-medal),
|
||||||
|
.scoreboard-table :deep(.col-time) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
78
app/modules/scoreboard/ModuleLayout.vue
Normal file
78
app/modules/scoreboard/ModuleLayout.vue
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<template>
|
||||||
|
<div class="scoreboard-module">
|
||||||
|
<slot name="header">
|
||||||
|
<header class="module-header">
|
||||||
|
<h1>{{ title }}</h1>
|
||||||
|
<p>{{ description }}</p>
|
||||||
|
</header>
|
||||||
|
</slot>
|
||||||
|
|
||||||
|
<div class="module-content">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="module-footer">
|
||||||
|
<slot name="footer">
|
||||||
|
<p>© {{ currentYear }} 运动会记分板系统 - 版权所有</p>
|
||||||
|
</slot>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
interface Props {
|
||||||
|
title?: string
|
||||||
|
description?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
title: '运动会记分板',
|
||||||
|
description: '运动会管理系统'
|
||||||
|
})
|
||||||
|
|
||||||
|
const currentYear = new Date().getFullYear()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.scoreboard-module {
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-header {
|
||||||
|
background-color: #304156;
|
||||||
|
color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-header h1 {
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-header p {
|
||||||
|
margin: 0;
|
||||||
|
opacity: 0.8;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-content {
|
||||||
|
flex: 1;
|
||||||
|
background-color: #f0f2f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-footer {
|
||||||
|
background-color: #fff;
|
||||||
|
border-top: 1px solid #e6e6e6;
|
||||||
|
padding: 12px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-footer p {
|
||||||
|
margin: 0;
|
||||||
|
color: #909399;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
155
app/modules/scoreboard/README.md
Normal file
155
app/modules/scoreboard/README.md
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
# 运动会记分板模块
|
||||||
|
|
||||||
|
可复用的运动会管理模块,提供完整的比赛项目、队伍、成绩管理功能。
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
modules/scoreboard/
|
||||||
|
├── index.ts # 模块配置和常量
|
||||||
|
├── api.ts # API 工具函数
|
||||||
|
├── mod.ts # 模块导出
|
||||||
|
├── ModuleLayout.vue # 模块布局组件
|
||||||
|
├── StatCard.vue # 统计卡片组件
|
||||||
|
└── DataTable.vue # 数据表格组件
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用方式
|
||||||
|
|
||||||
|
### 1. 导入配置常量
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import {
|
||||||
|
EVENT_CATEGORIES,
|
||||||
|
TEAM_GROUPS,
|
||||||
|
EVENT_TYPES,
|
||||||
|
SCORING_RULES
|
||||||
|
} from '~/modules/scoreboard'
|
||||||
|
|
||||||
|
// 使用示例
|
||||||
|
const categories = Object.values(EVENT_CATEGORIES)
|
||||||
|
// ['田赛', '径赛', '团体赛']
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 使用 API 函数
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import {
|
||||||
|
fetchEvents,
|
||||||
|
fetchTeams,
|
||||||
|
fetchResults,
|
||||||
|
fetchScoreboard,
|
||||||
|
createResult
|
||||||
|
} from '~/modules/scoreboard'
|
||||||
|
|
||||||
|
// 获取所有比赛项目
|
||||||
|
const events = await fetchEvents()
|
||||||
|
|
||||||
|
// 按类别筛选
|
||||||
|
const trackEvents = await fetchEvents({ category: '径赛' })
|
||||||
|
|
||||||
|
// 获取队伍
|
||||||
|
const teams = await fetchTeams({ group: '文化班甲组' })
|
||||||
|
|
||||||
|
// 录入成绩
|
||||||
|
await createResult({
|
||||||
|
event_id: 1,
|
||||||
|
team_id: 1,
|
||||||
|
score: '10.5',
|
||||||
|
rank: 1
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取记分板
|
||||||
|
const scoreboard = await fetchScoreboard()
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 使用 UI 组件
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<ModuleLayout title="运动会" description="管理系统">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="6">
|
||||||
|
<StatCard
|
||||||
|
icon="Trophy"
|
||||||
|
label="比赛项目"
|
||||||
|
:value="12"
|
||||||
|
color="#409eff"
|
||||||
|
/>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<DataTable :data="scoreboard" :columns="columns" />
|
||||||
|
</ModuleLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ModuleLayout, StatCard, DataTable } from '~/modules/scoreboard'
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{ prop: 'name', label: '队伍名称' },
|
||||||
|
{ prop: 'total_score', label: '总分', sortable: true }
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 积分规则
|
||||||
|
|
||||||
|
| 名次 | 积分 | 奖牌 |
|
||||||
|
|------|------|------|
|
||||||
|
| 第 1 名 | 7 分 | 金牌 |
|
||||||
|
| 第 2 名 | 5 分 | 银牌 |
|
||||||
|
| 第 3 名 | 3 分 | 铜牌 |
|
||||||
|
|
||||||
|
## 比赛项目
|
||||||
|
|
||||||
|
### 田赛
|
||||||
|
- 跳高(米)
|
||||||
|
- 跳远(米)
|
||||||
|
- 掷铅球(米)
|
||||||
|
|
||||||
|
### 径赛
|
||||||
|
- 100m(秒)
|
||||||
|
- 200m(秒)
|
||||||
|
- 400m(秒)
|
||||||
|
- 4×100m(秒)
|
||||||
|
- 4×400m(秒)
|
||||||
|
- 20×50m(秒)
|
||||||
|
|
||||||
|
### 团体赛
|
||||||
|
- 旱地龙舟(秒)
|
||||||
|
- 跳长绳(次)
|
||||||
|
- 折返跑(秒)
|
||||||
|
|
||||||
|
## 组别
|
||||||
|
|
||||||
|
- 教师组
|
||||||
|
- 航空班组
|
||||||
|
- 体育班组
|
||||||
|
- 文化班甲组
|
||||||
|
- 文化班乙组
|
||||||
|
|
||||||
|
## API 接口
|
||||||
|
|
||||||
|
| 接口 | 方法 | 描述 |
|
||||||
|
|------|------|------|
|
||||||
|
| `/api/config` | GET | 获取系统配置 |
|
||||||
|
| `/api/events` | GET/POST | 比赛项目管理 |
|
||||||
|
| `/api/teams` | GET/POST | 队伍管理 |
|
||||||
|
| `/api/results` | GET/POST | 成绩管理 |
|
||||||
|
| `/api/scoreboard` | GET | 记分板数据 |
|
||||||
|
| `/api/seed` | POST | 初始化数据 |
|
||||||
|
|
||||||
|
## 扩展模块
|
||||||
|
|
||||||
|
可以通过以下方式扩展模块功能:
|
||||||
|
|
||||||
|
1. 添加新的比赛项目类型
|
||||||
|
2. 自定义积分规则
|
||||||
|
3. 添加数据导出功能
|
||||||
|
4. 集成图表展示
|
||||||
|
5. 添加实时通知
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
66
app/modules/scoreboard/StatCard.vue
Normal file
66
app/modules/scoreboard/StatCard.vue
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<template>
|
||||||
|
<el-card class="stat-card">
|
||||||
|
<div class="stat-content">
|
||||||
|
<el-icon class="stat-icon" :color="color">
|
||||||
|
<component :is="icon" />
|
||||||
|
</el-icon>
|
||||||
|
<div class="stat-info">
|
||||||
|
<div class="stat-value">{{ value }}</div>
|
||||||
|
<div class="stat-label">{{ label }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
interface Props {
|
||||||
|
icon: string
|
||||||
|
label: string
|
||||||
|
value?: string | number
|
||||||
|
color?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
withDefaults(defineProps<Props>(), {
|
||||||
|
value: '0',
|
||||||
|
color: '#409eff'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.stat-card {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-icon {
|
||||||
|
font-size: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #909399;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.stat-value {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-icon {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
106
app/modules/scoreboard/api.ts
Normal file
106
app/modules/scoreboard/api.ts
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/**
|
||||||
|
* 记分板模块 API 工具函数
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配置信息
|
||||||
|
*/
|
||||||
|
export const fetchConfig = async () => {
|
||||||
|
const res = await $fetch('/api/config')
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取比赛项目列表
|
||||||
|
*/
|
||||||
|
export const fetchEvents = async (params?: { category?: string; group?: string }) => {
|
||||||
|
const query = new URLSearchParams()
|
||||||
|
if (params?.category) query.append('category', params.category)
|
||||||
|
if (params?.group) query.append('group', params.group)
|
||||||
|
const res = await $fetch(`/api/events?${query}`)
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建比赛项目
|
||||||
|
*/
|
||||||
|
export const createEvent = async (data: {
|
||||||
|
name: string
|
||||||
|
category: string
|
||||||
|
event_group: string
|
||||||
|
unit: string
|
||||||
|
}) => {
|
||||||
|
const res = await $fetch('/api/events', {
|
||||||
|
method: 'POST',
|
||||||
|
body: data
|
||||||
|
})
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取队伍列表
|
||||||
|
*/
|
||||||
|
export const fetchTeams = async (params?: { group?: string }) => {
|
||||||
|
const query = new URLSearchParams()
|
||||||
|
if (params?.group) query.append('group', params.group)
|
||||||
|
const res = await $fetch(`/api/teams?${query}`)
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建队伍
|
||||||
|
*/
|
||||||
|
export const createTeam = async (data: { name: string; team_group: string }) => {
|
||||||
|
const res = await $fetch('/api/teams', {
|
||||||
|
method: 'POST',
|
||||||
|
body: data
|
||||||
|
})
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取成绩列表
|
||||||
|
*/
|
||||||
|
export const fetchResults = async (params?: { event_id?: number; team_id?: number }) => {
|
||||||
|
const query = new URLSearchParams()
|
||||||
|
if (params?.event_id) query.append('event_id', String(params.event_id))
|
||||||
|
if (params?.team_id) query.append('team_id', String(params.team_id))
|
||||||
|
const res = await $fetch(`/api/results?${query}`)
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 录入成绩
|
||||||
|
*/
|
||||||
|
export const createResult = async (data: {
|
||||||
|
event_id: number
|
||||||
|
team_id: number
|
||||||
|
score: string
|
||||||
|
rank?: number
|
||||||
|
}) => {
|
||||||
|
const res = await $fetch('/api/results', {
|
||||||
|
method: 'POST',
|
||||||
|
body: data
|
||||||
|
})
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取记分板数据
|
||||||
|
*/
|
||||||
|
export const fetchScoreboard = async (params?: { group?: string }) => {
|
||||||
|
const query = new URLSearchParams()
|
||||||
|
if (params?.group) query.append('group', params.group)
|
||||||
|
const res = await $fetch(`/api/scoreboard?${query}`)
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化示例数据
|
||||||
|
*/
|
||||||
|
export const seedData = async () => {
|
||||||
|
const res = await $fetch('/api/seed', {
|
||||||
|
method: 'POST'
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
77
app/modules/scoreboard/index.ts
Normal file
77
app/modules/scoreboard/index.ts
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/**
|
||||||
|
* 运动会记分板系统模块
|
||||||
|
*
|
||||||
|
* 此模块提供完整的运动会管理功能
|
||||||
|
* 可作为独立模块集成到更大的系统中
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 模块配置
|
||||||
|
export const scoreboardModule = {
|
||||||
|
name: 'scoreboard',
|
||||||
|
version: '1.0.0',
|
||||||
|
description: '运动会记分板管理模块'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 比赛类别配置
|
||||||
|
export const EVENT_CATEGORIES = {
|
||||||
|
FIELD: '田赛',
|
||||||
|
TRACK: '径赛',
|
||||||
|
TEAM: '团体赛'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
// 组别配置
|
||||||
|
export const TEAM_GROUPS = {
|
||||||
|
TEACHER: '教师组',
|
||||||
|
AVIATION: '航空班组',
|
||||||
|
SPORTS: '体育班组',
|
||||||
|
CULTURE_A: '文化班甲组',
|
||||||
|
CULTURE_B: '文化班乙组'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
// 项目配置
|
||||||
|
export const EVENT_TYPES = {
|
||||||
|
[EVENT_CATEGORIES.FIELD]: [
|
||||||
|
{ name: '跳高', unit: '米' },
|
||||||
|
{ name: '跳远', unit: '米' },
|
||||||
|
{ name: '掷铅球', unit: '米' }
|
||||||
|
],
|
||||||
|
[EVENT_CATEGORIES.TRACK]: [
|
||||||
|
{ name: '100m', unit: '秒' },
|
||||||
|
{ name: '200m', unit: '秒' },
|
||||||
|
{ name: '400m', unit: '秒' },
|
||||||
|
{ name: '4×100m', unit: '秒' },
|
||||||
|
{ name: '4×400m', unit: '秒' },
|
||||||
|
{ name: '20×50m', unit: '秒' }
|
||||||
|
],
|
||||||
|
[EVENT_CATEGORIES.TEAM]: [
|
||||||
|
{ name: '旱地龙舟', unit: '秒' },
|
||||||
|
{ name: '跳长绳', unit: '次' },
|
||||||
|
{ name: '折返跑', unit: '秒' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 积分规则
|
||||||
|
export const SCORING_RULES = {
|
||||||
|
GOLD: { rank: 1, points: 7, medal: 'gold' },
|
||||||
|
SILVER: { rank: 2, points: 5, medal: 'silver' },
|
||||||
|
BRONZE: { rank: 3, points: 3, medal: 'bronze' }
|
||||||
|
}
|
||||||
|
|
||||||
|
// API 路由
|
||||||
|
export const API_ROUTES = {
|
||||||
|
EVENTS: '/api/events',
|
||||||
|
TEAMS: '/api/teams',
|
||||||
|
RESULTS: '/api/results',
|
||||||
|
SCOREBOARD: '/api/scoreboard',
|
||||||
|
CONFIG: '/api/config',
|
||||||
|
SEED: '/api/seed'
|
||||||
|
} as const
|
||||||
|
|
||||||
|
// 页面路由
|
||||||
|
export const PAGE_ROUTES = {
|
||||||
|
HOME: '/',
|
||||||
|
EVENTS: '/events',
|
||||||
|
TEAMS: '/teams',
|
||||||
|
RESULTS: '/results',
|
||||||
|
SCOREBOARD: '/scoreboard'
|
||||||
|
} as const
|
||||||
50
app/modules/scoreboard/mod.ts
Normal file
50
app/modules/scoreboard/mod.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* 运动会记分板模块导出
|
||||||
|
*
|
||||||
|
* 使用示例:
|
||||||
|
* ```ts
|
||||||
|
* import {
|
||||||
|
* EVENT_CATEGORIES,
|
||||||
|
* TEAM_GROUPS,
|
||||||
|
* EVENT_TYPES,
|
||||||
|
* SCORING_RULES,
|
||||||
|
* API_ROUTES,
|
||||||
|
* fetchEvents,
|
||||||
|
* fetchTeams,
|
||||||
|
* fetchResults,
|
||||||
|
* fetchScoreboard
|
||||||
|
* } from '~/modules/scoreboard'
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 配置常量
|
||||||
|
export {
|
||||||
|
EVENT_CATEGORIES,
|
||||||
|
TEAM_GROUPS,
|
||||||
|
EVENT_TYPES,
|
||||||
|
SCORING_RULES,
|
||||||
|
API_ROUTES,
|
||||||
|
PAGE_ROUTES,
|
||||||
|
scoreboardModule
|
||||||
|
} from './index'
|
||||||
|
|
||||||
|
// API 函数
|
||||||
|
export {
|
||||||
|
fetchConfig,
|
||||||
|
fetchEvents,
|
||||||
|
createEvent,
|
||||||
|
fetchTeams,
|
||||||
|
createTeam,
|
||||||
|
fetchResults,
|
||||||
|
createResult,
|
||||||
|
fetchScoreboard,
|
||||||
|
seedData
|
||||||
|
} from './api'
|
||||||
|
|
||||||
|
// Vue 组件
|
||||||
|
export { default as ModuleLayout } from './ModuleLayout.vue'
|
||||||
|
export { default as StatCard } from './StatCard.vue'
|
||||||
|
export { default as DataTable } from './DataTable.vue'
|
||||||
|
|
||||||
|
// 类型导出
|
||||||
|
export type { Column } from './DataTable.vue'
|
||||||
Loading…
x
Reference in New Issue
Block a user