laobinghu 4df5c13976 refactor: simplify dark mode with VueUse + Element Plus
Remove custom CSS variable overrides, use Element Plus built-in dark mode with VueUse useDark
2026-03-22 16:22:35 +08:00

221 lines
5.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="teams-container">
<el-card>
<template #header>
<div class="card-header">
<span>队伍管理</span>
<el-button type="primary" @click="showAddDialog = true">添加队伍</el-button>
</div>
</template>
<el-form :inline="true" class="filter-form">
<!-- 年级筛选 -->
<el-form-item label="年级">
<el-select v-model="filters.grade" placeholder="全部" clearable @change="onFilterChange">
<el-option v-for="g in config.grades" :key="g" :label="g" :value="g" />
</el-select>
</el-form-item>
<!-- 班级类型筛选 -->
<el-form-item label="班级类型">
<el-select v-model="filters.classType" placeholder="全部" clearable :disabled="!filters.grade" @change="onFilterChange">
<el-option v-for="c in config.classTypes" :key="c" :label="c" :value="c" />
</el-select>
</el-form-item>
<!-- 性别筛选 -->
<el-form-item label="性别">
<el-select v-model="filters.gender" placeholder="全部" clearable :disabled="!filters.grade" @change="onFilterChange">
<el-option v-for="g in config.genders" :key="g" :label="g" :value="g" />
</el-select>
</el-form-item>
</el-form>
<el-table :data="teams" border stripe class="teams-table">
<el-table-column prop="id" label="ID" width="80"></el-table-column>
<el-table-column prop="name" label="队伍名称"></el-table-column>
<el-table-column prop="team_group" label="组别" width="200" class-name="col-group"></el-table-column>
<el-table-column prop="created_at" label="创建时间" width="200" class-name="col-time">
<template #default="{ row }">
{{ new Date(row.created_at).toLocaleString('zh-CN') }}
</template>
</el-table-column>
</el-table>
</el-card>
<el-dialog v-model="showAddDialog" title="添加队伍" width="500px">
<el-form :model="form" label-width="100px">
<el-form-item label="队伍名称">
<el-input v-model="form.name" placeholder="请输入队伍名称" />
</el-form-item>
<el-form-item label="组别">
<el-select v-model="form.team_group" placeholder="请选择组别">
<el-option v-for="g in allGroupOptions" :key="g.value" :label="g.label" :value="g.value" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="showAddDialog = false">取消</el-button>
<el-button type="primary" @click="addTeam">确定</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ElMessage } from 'element-plus'
import { computed } from 'vue'
const teams = ref([])
const showAddDialog = ref(false)
const config = ref({
grades: [] as string[],
classTypes: [] as string[],
genders: [] as string[],
all: [] as string[]
})
const filters = ref({
grade: '',
classType: '',
gender: ''
})
const form = ref({
name: '',
team_group: ''
})
// 为添加队伍对话框生成所有可用的组别选项从config API获取
const allGroupOptions = computed(() => {
return (config.value.all || []).map(g => ({ value: g, label: g }))
})
const loadConfig = async () => {
try {
const res = await $fetch('/api/config')
config.value = res.data.groups
} catch (error) {
ElMessage.error('加载配置失败')
}
}
const loadTeams = async () => {
try {
const params = new URLSearchParams()
if (filters.value.grade) params.append('grade', filters.value.grade)
if (filters.value.classType) params.append('classType', filters.value.classType)
if (filters.value.gender) params.append('gender', filters.value.gender)
const res = await $fetch(`/api/teams?${params}`)
teams.value = res.data
} catch (error) {
ElMessage.error('加载队伍失败')
}
}
const onFilterChange = () => {
loadTeams()
}
const addTeam = async () => {
if (!form.value.name || !form.value.team_group) {
ElMessage.error('请填写完整信息')
return
}
try {
await $fetch('/api/teams', {
method: 'POST',
body: form.value
})
ElMessage.success('添加成功')
showAddDialog.value = false
form.value = { name: '', team_group: '' }
loadTeams()
} catch (error) {
ElMessage.error('添加失败')
}
}
onMounted(() => {
loadConfig()
loadTeams()
})
</script>
<style scoped>
.teams-container {
max-width: 1200px;
margin: 0 auto;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.card-header span {
color: var(--el-text-color-primary);
font-size: 18px;
font-weight: 600;
}
.filter-form {
margin-bottom: 20px;
}
/* 确保表格和表单在暗色模式下文字清晰 */
:deep(.el-card) {
background-color: var(--header-bg);
color: var(--el-text-color-primary);
}
:deep(.el-card .el-card__header) {
border-bottom-color: var(--el-border-color);
}
:deep(.el-form-item__label) {
color: var(--el-text-color-primary) !important;
}
:deep(.el-table) {
color: var(--el-text-color-primary);
}
:deep(.el-table th) {
background-color: var(--header-bg);
color: var(--el-text-color-primary);
}
:deep(.el-table tr) {
background-color: var(--header-bg);
}
:deep(.el-table td) {
color: var(--el-text-color-primary);
}
@media (max-width: 900px) {
.card-header {
flex-direction: column;
align-items: flex-start;
gap: 10px;
}
.filter-form :deep(.el-form-item) {
margin-right: 0;
width: 100%;
}
.filter-form :deep(.el-select) {
width: 100%;
}
.teams-table :deep(.col-time) {
display: none;
}
}
</style>