feat(dashboard): 新增比赛管理仪表盘功能
添加比赛管理仪表盘页面,包含比赛卡片列表、状态标签和新增功能 移除旧的mine页面和相关路由配置 强制设置i18n语言为中文并更新系统标题 更新VSCode设置中的typescript格式化工具
This commit is contained in:
@ -4,7 +4,6 @@ import { getPaletteColorByNumber, mixColor } from '@sa/color'
|
||||
import { computed } from 'vue'
|
||||
import { loginModuleRecord } from '@/constants/app'
|
||||
import { $t } from '@/locales'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { useThemeStore } from '@/store/modules/theme'
|
||||
import BindWechat from './modules/bind-wechat.vue'
|
||||
import CodeLogin from './modules/code-login.vue'
|
||||
@ -19,7 +18,7 @@ interface Props {
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const appStore = useAppStore()
|
||||
// const appStore = useAppStore()
|
||||
const themeStore = useThemeStore()
|
||||
|
||||
interface LoginModule {
|
||||
@ -67,13 +66,13 @@ const bgColor = computed(() => {
|
||||
class="text-20px lt-sm:text-18px"
|
||||
@switch="themeStore.toggleThemeScheme"
|
||||
/>
|
||||
<LangSwitch
|
||||
<!-- <LangSwitch
|
||||
v-if="themeStore.header.multilingual.visible"
|
||||
:lang="appStore.locale"
|
||||
:lang-options="appStore.localeOptions"
|
||||
:show-tooltip="false"
|
||||
@change-lang="appStore.changeLocale"
|
||||
/>
|
||||
/> -->
|
||||
</div>
|
||||
</header>
|
||||
<main class="pt-24px">
|
||||
|
||||
@ -48,6 +48,7 @@ interface Account {
|
||||
password: string
|
||||
}
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
const accounts = computed<Account[]>(() => [
|
||||
{
|
||||
key: 'super',
|
||||
@ -69,6 +70,7 @@ const accounts = computed<Account[]>(() => [
|
||||
},
|
||||
])
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
async function handleAccountLogin(account: Account) {
|
||||
await authStore.login(account.userName, account.password)
|
||||
}
|
||||
@ -105,14 +107,14 @@ async function handleAccountLogin(account: Account) {
|
||||
{{ $t(loginModuleRecord.register) }}
|
||||
</NButton>
|
||||
</div>
|
||||
<NDivider class="text-14px text-#666 !m-0">
|
||||
<!-- <NDivider class="text-14px text-#666 !m-0">
|
||||
{{ $t('page.login.pwdLogin.otherAccountLogin') }}
|
||||
</NDivider>
|
||||
<div class="flex-center gap-12px">
|
||||
</NDivider> -->
|
||||
<!-- <div class="flex-center gap-12px">
|
||||
<NButton v-for="item in accounts" :key="item.key" type="primary" @click="handleAccountLogin(item)">
|
||||
{{ item.label }}
|
||||
</NButton>
|
||||
</div>
|
||||
</div> -->
|
||||
</NSpace>
|
||||
</NForm>
|
||||
</template>
|
||||
|
||||
55
apps/admin/src/views/dashboard/index.vue
Normal file
55
apps/admin/src/views/dashboard/index.vue
Normal file
@ -0,0 +1,55 @@
|
||||
<script setup lang="ts">
|
||||
import { NButton, NGi, NGrid, NSpace } from 'naive-ui'
|
||||
import { computed } from 'vue'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import CompetitionCard from './modules/competition-card.vue'
|
||||
import { competitionList } from './modules/data'
|
||||
|
||||
// 引入 store 用于判断移动端布局 (与你提供的风格保持一致)
|
||||
const appStore = useAppStore()
|
||||
const gap = computed(() => (appStore.isMobile ? 12 : 16))
|
||||
|
||||
// 模拟新增操作
|
||||
function handleAdd() {
|
||||
window.$message?.success('点击了新增比赛活动')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NSpace vertical :size="24">
|
||||
<!-- 顶部 Header 区域 -->
|
||||
<div class="flex flex-col justify-between gap-4 sm:flex-row sm:items-center">
|
||||
<div>
|
||||
<h2 class="m-0 text-xl text-gray-800 font-bold dark:text-white">
|
||||
比赛列表
|
||||
</h2>
|
||||
<p class="mt-1 text-sm text-gray-500">
|
||||
管理并配置所有阅读大比拼活动
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<NButton type="primary" size="medium" class="px-6 font-medium" @click="handleAdd">
|
||||
<template #icon>
|
||||
<div class="i-carbon-add text-lg" />
|
||||
</template>
|
||||
新增比赛活动
|
||||
</NButton>
|
||||
</div>
|
||||
|
||||
<!-- 卡片列表区域 -->
|
||||
<!-- 响应式布局:手机1列,平板2列,中屏3列,大屏4列 -->
|
||||
<NGrid :x-gap="gap" :y-gap="gap" responsive="screen" item-responsive>
|
||||
<NGi
|
||||
v-for="item in competitionList"
|
||||
:key="item.id"
|
||||
span="24 s:12 m:8 l:6"
|
||||
>
|
||||
<CompetitionCard :item="item" />
|
||||
</NGi>
|
||||
</NGrid>
|
||||
</NSpace>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* 针对不同屏幕微调间距 */
|
||||
</style>
|
||||
84
apps/admin/src/views/dashboard/modules/competition-card.vue
Normal file
84
apps/admin/src/views/dashboard/modules/competition-card.vue
Normal file
@ -0,0 +1,84 @@
|
||||
<script setup lang="ts">
|
||||
import type { CompetitionItem } from './data'
|
||||
import { NButton, NCard, NTag } from 'naive-ui'
|
||||
import { computed } from 'vue'
|
||||
|
||||
interface Props {
|
||||
item: CompetitionItem
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
// 状态配置:颜色和文本
|
||||
const statusConfig = computed(() => {
|
||||
if (props.item.status === 'ongoing') {
|
||||
return { type: 'success', text: '进行中', bgClass: 'bg-green-100 text-green-600' }
|
||||
}
|
||||
return { type: 'default', text: '未开始', bgClass: 'bg-gray-100 text-gray-500' }
|
||||
})
|
||||
|
||||
// 处理标题换行
|
||||
const formattedTitle = computed(() => props.item.title.replace(/\n/g, '<br/>'))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NCard
|
||||
:bordered="false"
|
||||
class="group relative h-full overflow-hidden rounded-2xl transition-all duration-300 hover:shadow-lg"
|
||||
content-style="padding: 24px; display: flex; flex-direction: column; height: 100%;"
|
||||
>
|
||||
<!-- 特殊背景装饰 (仅高亮卡片显示) -->
|
||||
<div
|
||||
v-if="item.isHighlight"
|
||||
class="pointer-events-none absolute right-0 top-0 z-0 h-32 w-32 rounded-bl-full bg-blue-50/80 -mr-8 -mt-8"
|
||||
/>
|
||||
|
||||
<div class="relative z-10 h-full flex flex-col justify-between">
|
||||
<!-- 顶部内容 -->
|
||||
<div>
|
||||
<!-- 状态标签 -->
|
||||
<div class="mb-4">
|
||||
<NTag
|
||||
:bordered="false"
|
||||
size="small"
|
||||
round
|
||||
class="px-3 font-medium" :class="[statusConfig.bgClass]"
|
||||
>
|
||||
{{ statusConfig.text }}
|
||||
</NTag>
|
||||
</div>
|
||||
|
||||
<!-- 标题 -->
|
||||
<h3
|
||||
class="mb-3 min-h-[3rem] text-lg text-gray-800 font-bold leading-tight dark:text-white"
|
||||
v-html="formattedTitle"
|
||||
/>
|
||||
|
||||
<!-- 日期 -->
|
||||
<div class="mb-6 flex items-center text-sm text-gray-400">
|
||||
<div class="i-carbon-calendar mr-2 text-base" />
|
||||
<span>{{ item.date }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部内容 -->
|
||||
<div class="flex items-center justify-between border-t border-gray-50 pt-4 dark:border-gray-800">
|
||||
<span class="text-xs text-gray-500 font-medium">
|
||||
{{ item.teamCount }} 支参赛队伍
|
||||
</span>
|
||||
<NButton
|
||||
text
|
||||
type="primary"
|
||||
size="small"
|
||||
class="font-bold hover:underline"
|
||||
>
|
||||
查看配置详情
|
||||
</NButton>
|
||||
</div>
|
||||
</div>
|
||||
</NCard>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* 可选:微调样式 */
|
||||
</style>
|
||||
70
apps/admin/src/views/dashboard/modules/data.ts
Normal file
70
apps/admin/src/views/dashboard/modules/data.ts
Normal file
@ -0,0 +1,70 @@
|
||||
// src/views/competition/modules/data.ts
|
||||
|
||||
export interface CompetitionItem {
|
||||
id: string
|
||||
title: string
|
||||
date: string
|
||||
teamCount: number
|
||||
status: 'ongoing' | 'pending' // ongoing: 进行中, pending: 未开始
|
||||
isHighlight?: boolean // 用于标记第一个卡片的特殊背景
|
||||
}
|
||||
|
||||
export const competitionList: CompetitionItem[] = [
|
||||
{
|
||||
id: '1',
|
||||
title: '阅读之星大赛\n辞海遨游环节', // 使用换行符或在组件中处理换行
|
||||
date: '2026.01.12',
|
||||
teamCount: 40,
|
||||
status: 'ongoing',
|
||||
isHighlight: true,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: '诗词大会总决赛',
|
||||
date: '2026.01.12',
|
||||
teamCount: 32,
|
||||
status: 'pending',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: '趣味百科大作战',
|
||||
date: '2026.01.12',
|
||||
teamCount: 32,
|
||||
status: 'pending',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
title: '经典文学研读周',
|
||||
date: '2026.01.12',
|
||||
teamCount: 32,
|
||||
status: 'pending',
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
title: '未来科学家阅读赛',
|
||||
date: '2026.01.12',
|
||||
teamCount: 32,
|
||||
status: 'pending',
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
title: '历史人文知识赛',
|
||||
date: '2026.01.12',
|
||||
teamCount: 32,
|
||||
status: 'pending',
|
||||
},
|
||||
{
|
||||
id: '7',
|
||||
title: '少儿绘本创意营',
|
||||
date: '2026.01.12',
|
||||
teamCount: 32,
|
||||
status: 'pending',
|
||||
},
|
||||
{
|
||||
id: '8',
|
||||
title: '唐诗三百首挑战',
|
||||
date: '2026.01.12',
|
||||
teamCount: 32,
|
||||
status: 'pending',
|
||||
},
|
||||
]
|
||||
@ -1,9 +0,0 @@
|
||||
<script lang="ts" setup></script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h1>Mine</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
Reference in New Issue
Block a user