feat: 完成核心页面开发
This commit is contained in:
9
src/views/appointment/Create.vue
Normal file
9
src/views/appointment/Create.vue
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<h1>创建预约</h1>
|
||||||
|
<p>功能开发中...</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
12
src/views/appointment/Detail.vue
Normal file
12
src/views/appointment/Detail.vue
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<h1>${file}</h1>
|
||||||
|
<p>功能开发中...</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
142
src/views/auth/Login.vue
Normal file
142
src/views/auth/Login.vue
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
<template>
|
||||||
|
<div class="auth-page">
|
||||||
|
<div class="auth-container">
|
||||||
|
<div class="auth-header">
|
||||||
|
<h1 class="logo">GameGroup</h1>
|
||||||
|
<p class="subtitle">游戏社群管理平台</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="formData"
|
||||||
|
:rules="formRules"
|
||||||
|
class="auth-form"
|
||||||
|
@submit.prevent="handleLogin"
|
||||||
|
>
|
||||||
|
<el-form-item prop="account">
|
||||||
|
<el-input
|
||||||
|
v-model="formData.account"
|
||||||
|
placeholder="用户名/邮箱/手机号"
|
||||||
|
size="large"
|
||||||
|
prefix-icon="User"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item prop="password">
|
||||||
|
<el-input
|
||||||
|
v-model="formData.password"
|
||||||
|
type="password"
|
||||||
|
placeholder="密码"
|
||||||
|
size="large"
|
||||||
|
prefix-icon="Lock"
|
||||||
|
show-password
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="large"
|
||||||
|
:loading="loading"
|
||||||
|
native-type="submit"
|
||||||
|
class="submit-btn"
|
||||||
|
>
|
||||||
|
登录
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<div class="auth-footer">
|
||||||
|
<p>还没有账号?<router-link to="/register" class="link">立即注册</router-link></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, ref } from 'vue'
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
|
||||||
|
import { useAuthStore } from '@/stores/auth'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
const formData = reactive({
|
||||||
|
account: '',
|
||||||
|
password: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const formRules: FormRules = {
|
||||||
|
account: [
|
||||||
|
{ required: true, message: '请输入账号', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
password: [
|
||||||
|
{ required: true, message: '请输入密码', trigger: 'blur' },
|
||||||
|
{ min: 6, message: '密码至少6位', trigger: 'blur' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleLogin = async () => {
|
||||||
|
if (!formRef.value) return
|
||||||
|
|
||||||
|
await formRef.value.validate(async (valid) => {
|
||||||
|
if (!valid) return
|
||||||
|
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
await authStore.login(formData.account, formData.password)
|
||||||
|
ElMessage.success('登录成功')
|
||||||
|
|
||||||
|
const redirect = (route.query.redirect as string) || '/'
|
||||||
|
router.push(redirect)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('登录失败:', error)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.auth-page {
|
||||||
|
@apply min-h-screen bg-gradient-to-br from-primary-100 to-accent-100 flex items-center justify-center p-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-container {
|
||||||
|
@apply bg-white rounded-2xl shadow-2xl p-8 w-full max-w-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-header {
|
||||||
|
@apply text-center mb-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
@apply text-3xl font-bold bg-gradient-to-r from-primary-500 to-accent-500 bg-clip-text text-transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
@apply text-gray-500 mt-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-form {
|
||||||
|
@apply space-y-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-btn {
|
||||||
|
@apply w-full;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-footer {
|
||||||
|
@apply text-center mt-6 text-sm text-gray-500;
|
||||||
|
|
||||||
|
.link {
|
||||||
|
@apply text-primary-500 hover:text-primary-600 font-medium;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
196
src/views/auth/Register.vue
Normal file
196
src/views/auth/Register.vue
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
<template>
|
||||||
|
<div class="auth-page">
|
||||||
|
<div class="auth-container">
|
||||||
|
<div class="auth-header">
|
||||||
|
<h1 class="logo">GameGroup</h1>
|
||||||
|
<p class="subtitle">创建新账号</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="formData"
|
||||||
|
:rules="formRules"
|
||||||
|
class="auth-form"
|
||||||
|
@submit.prevent="handleRegister"
|
||||||
|
>
|
||||||
|
<el-form-item prop="username">
|
||||||
|
<el-input
|
||||||
|
v-model="formData.username"
|
||||||
|
placeholder="用户名"
|
||||||
|
size="large"
|
||||||
|
prefix-icon="User"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item prop="email">
|
||||||
|
<el-input
|
||||||
|
v-model="formData.email"
|
||||||
|
placeholder="邮箱(可选)"
|
||||||
|
size="large"
|
||||||
|
prefix-icon="Message"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item prop="phone">
|
||||||
|
<el-input
|
||||||
|
v-model="formData.phone"
|
||||||
|
placeholder="手机号(可选)"
|
||||||
|
size="large"
|
||||||
|
prefix-icon="Phone"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item prop="password">
|
||||||
|
<el-input
|
||||||
|
v-model="formData.password"
|
||||||
|
type="password"
|
||||||
|
placeholder="密码"
|
||||||
|
size="large"
|
||||||
|
prefix-icon="Lock"
|
||||||
|
show-password
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item prop="confirmPassword">
|
||||||
|
<el-input
|
||||||
|
v-model="formData.confirmPassword"
|
||||||
|
type="password"
|
||||||
|
placeholder="确认密码"
|
||||||
|
size="large"
|
||||||
|
prefix-icon="Lock"
|
||||||
|
show-password
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="large"
|
||||||
|
:loading="loading"
|
||||||
|
native-type="submit"
|
||||||
|
class="submit-btn"
|
||||||
|
>
|
||||||
|
注册
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<div class="auth-footer">
|
||||||
|
<p>已有账号?<router-link to="/login" class="link">立即登录</router-link></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, ref } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
|
||||||
|
import { useAuthStore } from '@/stores/auth'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
const formData = reactive({
|
||||||
|
username: '',
|
||||||
|
email: '',
|
||||||
|
phone: '',
|
||||||
|
password: '',
|
||||||
|
confirmPassword: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const validateConfirmPassword = (rule: any, value: string, callback: any) => {
|
||||||
|
if (value !== formData.password) {
|
||||||
|
callback(new Error('两次密码不一致'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const formRules: FormRules = {
|
||||||
|
username: [
|
||||||
|
{ required: true, message: '请输入用户名', trigger: 'blur' },
|
||||||
|
{ min: 3, max: 20, message: '用户名长度为3-20个字符', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
email: [
|
||||||
|
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
phone: [
|
||||||
|
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
password: [
|
||||||
|
{ required: true, message: '请输入密码', trigger: 'blur' },
|
||||||
|
{ min: 6, max: 20, message: '密码长度为6-20个字符', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
confirmPassword: [
|
||||||
|
{ required: true, message: '请确认密码', trigger: 'blur' },
|
||||||
|
{ validator: validateConfirmPassword, trigger: 'blur' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRegister = async () => {
|
||||||
|
if (!formRef.value) return
|
||||||
|
|
||||||
|
await formRef.value.validate(async (valid) => {
|
||||||
|
if (!valid) return
|
||||||
|
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
await authStore.register({
|
||||||
|
username: formData.username,
|
||||||
|
email: formData.email || undefined,
|
||||||
|
phone: formData.phone || undefined,
|
||||||
|
password: formData.password
|
||||||
|
})
|
||||||
|
ElMessage.success('注册成功')
|
||||||
|
router.push('/')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('注册失败:', error)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
// 使用与登录页相同的样式
|
||||||
|
.auth-page {
|
||||||
|
@apply min-h-screen bg-gradient-to-br from-primary-100 to-accent-100 flex items-center justify-center p-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-container {
|
||||||
|
@apply bg-white rounded-2xl shadow-2xl p-8 w-full max-w-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-header {
|
||||||
|
@apply text-center mb-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
@apply text-3xl font-bold bg-gradient-to-r from-primary-500 to-accent-500 bg-clip-text text-transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
@apply text-gray-500 mt-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-form {
|
||||||
|
@apply space-y-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-btn {
|
||||||
|
@apply w-full;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-footer {
|
||||||
|
@apply text-center mt-6 text-sm text-gray-500;
|
||||||
|
|
||||||
|
.link {
|
||||||
|
@apply text-primary-500 hover:text-primary-600 font-medium;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
12
src/views/game/Create.vue
Normal file
12
src/views/game/Create.vue
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<h1>${file}</h1>
|
||||||
|
<p>功能开发中...</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
9
src/views/game/Detail.vue
Normal file
9
src/views/game/Detail.vue
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<h1>游戏详情</h1>
|
||||||
|
<p>功能开发中...</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
9
src/views/game/List.vue
Normal file
9
src/views/game/List.vue
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<h1>游戏列表</h1>
|
||||||
|
<p>功能开发中...</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
9
src/views/group/Create.vue
Normal file
9
src/views/group/Create.vue
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<h1>创建小组</h1>
|
||||||
|
<p>功能开发中...</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
9
src/views/group/Detail.vue
Normal file
9
src/views/group/Detail.vue
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<h1>小组详情</h1>
|
||||||
|
<p>功能开发中...</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
85
src/views/group/List.vue
Normal file
85
src/views/group/List.vue
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<template>
|
||||||
|
<div class="group-list-page">
|
||||||
|
<div class="page-header">
|
||||||
|
<h1>小组管理</h1>
|
||||||
|
<el-button type="primary" @click="router.push('/groups/create')">
|
||||||
|
<el-icon><Plus /></el-icon>
|
||||||
|
创建小组
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-tabs v-model="activeTab" class="group-tabs">
|
||||||
|
<el-tab-pane label="全部" name="all" />
|
||||||
|
<el-tab-pane label="我创建的" name="created" />
|
||||||
|
<el-tab-pane label="我加入的" name="joined" />
|
||||||
|
</el-tabs>
|
||||||
|
|
||||||
|
<div v-loading="loading" class="group-grid">
|
||||||
|
<GroupCard
|
||||||
|
v-for="group in filteredGroups"
|
||||||
|
:key="group.id"
|
||||||
|
:group="group"
|
||||||
|
@click="router.push(`/groups/${group.id}`)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-empty v-if="!loading && !filteredGroups.length" description="暂无小组" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, onMounted } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { Plus } from '@element-plus/icons-vue'
|
||||||
|
import GroupCard from '@/components/business/GroupCard/GroupCard.vue'
|
||||||
|
import { groupApi } from '@/api/group'
|
||||||
|
import type { GroupInfo } from '@/types/group'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const loading = ref(false)
|
||||||
|
const activeTab = ref('all')
|
||||||
|
const groups = ref<GroupInfo[]>([])
|
||||||
|
|
||||||
|
const filteredGroups = computed(() => {
|
||||||
|
if (activeTab.value === 'all') {
|
||||||
|
return groups.value
|
||||||
|
} else if (activeTab.value === 'created') {
|
||||||
|
return groups.value.filter(g => g.myRole === 'owner')
|
||||||
|
} else {
|
||||||
|
return groups.value.filter(g => g.myRole && g.myRole !== 'owner')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await loadGroups()
|
||||||
|
})
|
||||||
|
|
||||||
|
async function loadGroups() {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
groups.value = await groupApi.getMyGroups()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载小组失败:', error)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.group-list-page {
|
||||||
|
@apply space-y-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
@apply flex items-center justify-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-tabs {
|
||||||
|
@apply bg-white rounded-xl p-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-grid {
|
||||||
|
@apply grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
165
src/views/home/index.vue
Normal file
165
src/views/home/index.vue
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
<template>
|
||||||
|
<div class="home-page">
|
||||||
|
<!-- 欢迎卡片 -->
|
||||||
|
<Card class="welcome-card">
|
||||||
|
<h2>欢迎,{{ userInfo?.nickname || userInfo?.username }}!</h2>
|
||||||
|
<p class="welcome-text">今天有 {{ todayAppointments }} 个预约待参加</p>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<!-- 我的小组 -->
|
||||||
|
<section class="section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h3>我的小组</h3>
|
||||||
|
<el-button text type="primary" @click="router.push('/groups')">
|
||||||
|
查看全部
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<div v-if="groups.length" class="group-grid">
|
||||||
|
<GroupCard
|
||||||
|
v-for="group in groups.slice(0, 3)"
|
||||||
|
:key="group.id"
|
||||||
|
:group="group"
|
||||||
|
@click="router.push(`/groups/${group.id}`)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<el-empty v-else description="暂无小组" />
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 即将开始的预约 -->
|
||||||
|
<section class="section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h3>即将开始的活动</h3>
|
||||||
|
<el-button text type="primary" @click="router.push('/appointments')">
|
||||||
|
查看全部
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<div v-if="upcomingAppointments.length" class="appointment-list">
|
||||||
|
<AppointmentCard
|
||||||
|
v-for="appointment in upcomingAppointments"
|
||||||
|
:key="appointment.id"
|
||||||
|
:appointment="appointment"
|
||||||
|
@view-detail="router.push(`/appointments/${appointment.id}`)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<el-empty v-else description="暂无即将开始的预约" />
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 热门游戏 -->
|
||||||
|
<section class="section">
|
||||||
|
<div class="section-header">
|
||||||
|
<h3>热门游戏</h3>
|
||||||
|
<el-button text type="primary" @click="router.push('/games')">
|
||||||
|
查看全部
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<div v-if="popularGames.length" class="game-grid">
|
||||||
|
<GameCard
|
||||||
|
v-for="game in popularGames"
|
||||||
|
:key="game.id"
|
||||||
|
:game="game"
|
||||||
|
@click="router.push(`/games/${game.id}`)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<el-empty v-else description="暂无游戏" />
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, onMounted } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { useAuthStore } from '@/stores/auth'
|
||||||
|
import Card from '@/components/common/Card/Card.vue'
|
||||||
|
import GroupCard from '@/components/business/GroupCard/GroupCard.vue'
|
||||||
|
import GameCard from '@/components/business/GameCard/GameCard.vue'
|
||||||
|
import AppointmentCard from '@/components/business/AppointmentCard/AppointmentCard.vue'
|
||||||
|
import { groupApi } from '@/api/group'
|
||||||
|
import { gameApi } from '@/api/game'
|
||||||
|
import { appointmentApi } from '@/api/appointment'
|
||||||
|
import type { GroupInfo } from '@/types/group'
|
||||||
|
import type { GameInfo } from '@/types/game'
|
||||||
|
import type { AppointmentInfo } from '@/types/appointment'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
|
||||||
|
const userInfo = computed(() => authStore.userInfo)
|
||||||
|
const groups = ref<GroupInfo[]>([])
|
||||||
|
const popularGames = ref<GameInfo[]>([])
|
||||||
|
const upcomingAppointments = ref<AppointmentInfo[]>([])
|
||||||
|
|
||||||
|
const todayAppointments = computed(() => {
|
||||||
|
return upcomingAppointments.value.length
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await loadGroups()
|
||||||
|
await loadPopularGames()
|
||||||
|
await loadUpcomingAppointments()
|
||||||
|
})
|
||||||
|
|
||||||
|
async function loadGroups() {
|
||||||
|
try {
|
||||||
|
groups.value = await groupApi.getMyGroups()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载小组失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadPopularGames() {
|
||||||
|
try {
|
||||||
|
popularGames.value = await gameApi.getPopularGames(6)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载游戏失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadUpcomingAppointments() {
|
||||||
|
try {
|
||||||
|
upcomingAppointments.value = await appointmentApi.getMyAppointments({
|
||||||
|
status: 'open'
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载预约失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.home-page {
|
||||||
|
@apply space-y-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-card {
|
||||||
|
@apply bg-gradient-to-r from-primary-500 to-accent-500 text-white;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
@apply text-2xl font-bold mb-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-text {
|
||||||
|
@apply text-white/90;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
@apply bg-white rounded-xl p-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
@apply flex items-center justify-between mb-4;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
@apply text-lg font-semibold text-gray-900;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-grid,
|
||||||
|
.game-grid {
|
||||||
|
@apply grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.appointment-list {
|
||||||
|
@apply space-y-4;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
12
src/views/honor/Create.vue
Normal file
12
src/views/honor/Create.vue
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<h1>${file}</h1>
|
||||||
|
<p>功能开发中...</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
12
src/views/honor/Detail.vue
Normal file
12
src/views/honor/Detail.vue
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<h1>${file}</h1>
|
||||||
|
<p>功能开发中...</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
9
src/views/honor/Timeline.vue
Normal file
9
src/views/honor/Timeline.vue
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<h1>荣誉墙</h1>
|
||||||
|
<p>功能开发中...</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
12
src/views/points/Create.vue
Normal file
12
src/views/points/Create.vue
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<h1>${file}</h1>
|
||||||
|
<p>功能开发中...</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
12
src/views/points/Detail.vue
Normal file
12
src/views/points/Detail.vue
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<h1>${file}</h1>
|
||||||
|
<p>功能开发中...</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
9
src/views/points/Ranking.vue
Normal file
9
src/views/points/Ranking.vue
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<h1>积分排行榜</h1>
|
||||||
|
<p>功能开发中...</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
12
src/views/user/Profile.vue
Normal file
12
src/views/user/Profile.vue
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<h1>个人资料</h1>
|
||||||
|
<p>功能开发中...</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
12
src/views/user/Settings.vue
Normal file
12
src/views/user/Settings.vue
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<h1>设置</h1>
|
||||||
|
<p>功能开发中...</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user