refactor: home

This commit is contained in:
skytek_xinliang
2026-06-09 16:12:49 +08:00
parent 915f3b7f2f
commit afbdea6b13
+57 -129
View File
@@ -2,7 +2,8 @@
import { mdiEyeOutline, mdiFolderOutline } from '@mdi/js' import { mdiEyeOutline, mdiFolderOutline } from '@mdi/js'
import { useHomePage } from '@/composables/page-drivers/useHomePage' import { useHomePage } from '@/composables/page-drivers/useHomePage'
const { handleMessageCenter, handleNews, handleQuick, isNewsDialogOpen, pageModel, selectedNews } = useHomePage() const { handleMessageCenter, handleNews, handleQuick, isNewsDialogOpen, pageModel, selectedNews } =
useHomePage()
interface NewsItem { interface NewsItem {
id: number id: number
@@ -24,63 +25,55 @@ function resolveNewsItem(wrapped: unknown): NewsItem {
</script> </script>
<template> <template>
<v-container class="pa-0" fluid> <v-sheet>
<div class="d-flex flex-column ga-5 pt-1 pb-4 pr-2 pl-0"> <v-container fluid class="pa-0 px-2">
<v-sheet <v-card variant="flat">
class="d-flex flex-column flex-sm-row align-start align-sm-center ga-4 pa-5 elevation-1" <v-card-title> 歡迎使用校務資訊系統 </v-card-title>
color="surface" <v-card-text class="text-grey">
>
<v-avatar color="primary" size="52" variant="tonal">
<span class="text-h5">👋</span>
</v-avatar>
<div>
<div class="text-h5 font-weight-bold">歡迎使用校務資訊系統</div>
<div class="text-body-2 text-medium-emphasis mt-1">
使用頂部搜尋框快速找到功能或從左側選單瀏覽所有系統模組 使用頂部搜尋框快速找到功能或從左側選單瀏覽所有系統模組
</div> </v-card-text>
</div> </v-card>
</v-sheet>
<section class="d-flex flex-column"> <v-card variant="flat" border="thin primary" class="pa-4">
<div class="d-flex align-center ga-2 text-h6 font-weight-bold">📰 最新消息</div> <v-card-title class="mb-4"> 最新消息 </v-card-title>
<v-data-iterator class="mt-2" item-key="id" :items="pageModel.newsItems" :items-per-page="-1"> <v-data-iterator item-key="id" :items="pageModel.newsItems" :items-per-page="-1">
<template #default="{ items }"> <template #default="{ items }">
<v-row density="compact"> <v-row density="compact">
<v-col v-for="wrapped in items" :key="resolveNewsItem(wrapped).id" cols="12"> <v-col v-for="wrapped in items" :key="resolveNewsItem(wrapped).id" cols="12">
<v-card <v-card @click="handleNews(resolveNewsItem(wrapped))">
class="news-item d-flex flex-column flex-sm-row ga-4 pa-4 bg-surface" <div class="d-flex flex-no-wrap">
variant="outlined" <v-avatar rounded="0" size="64" class="flex-column bg-primary">
@click="handleNews(resolveNewsItem(wrapped))" <div>
> {{ resolveNewsItem(wrapped).date }}
<v-sheet class="news-badge"> </div>
<div class="news-badge-date">{{ resolveNewsItem(wrapped).date }}</div> <div>
<div class="news-badge-month">{{ resolveNewsItem(wrapped).month }}</div> {{ resolveNewsItem(wrapped).month }}
</v-sheet> </div>
<div class="flex-grow-1"> </v-avatar>
<div class="d-flex flex-wrap align-center font-weight-bold"> <div class="flex-fill">
<v-card-title>
{{ resolveNewsItem(wrapped).title }} {{ resolveNewsItem(wrapped).title }}
<v-chip <v-chip
v-if="resolveNewsItem(wrapped).isNew" v-if="resolveNewsItem(wrapped).isNew"
class="ml-2" class="ml-2"
color="primary" color="yellow"
size="x-small" size="x-small"
variant="flat" variant="flat"
> >
NEW NEW
</v-chip> </v-chip>
</div> </v-card-title>
<div class="text-body-2 text-medium-emphasis mt-2"> <v-card-text class="pa-4">
{{ resolveNewsItem(wrapped).desc }} {{ resolveNewsItem(wrapped).desc }}
</div> </v-card-text>
<div class="d-flex ga-4 mt-3 text-caption text-medium-emphasis"> <v-card-text class="pt-0">
<div class="d-flex align-center ga-1"> <v-row align="center">
<v-icon size="14" :icon="mdiFolderOutline" /> <v-icon size="14" :icon="mdiFolderOutline" />
<span>{{ resolveNewsItem(wrapped).dept }}</span> <v-col cols="1"> {{ resolveNewsItem(wrapped).dept }}</v-col>
</div>
<div class="d-flex align-center ga-1">
<v-icon size="14" :icon="mdiEyeOutline" /> <v-icon size="14" :icon="mdiEyeOutline" />
<span>{{ resolveNewsItem(wrapped).views }} 次瀏覽</span> <v-col>{{ resolveNewsItem(wrapped).views }} 次瀏覽</v-col>
</div> </v-row>
</v-card-text>
</div> </div>
</div> </div>
</v-card> </v-card>
@@ -88,116 +81,51 @@ function resolveNewsItem(wrapped: unknown): NewsItem {
</v-row> </v-row>
</template> </template>
</v-data-iterator> </v-data-iterator>
</section>
<v-card
class="d-flex align-center justify-space-between ga-3 px-5 py-4"
color="secondary"
rounded="xl"
variant="tonal"
@click="handleMessageCenter"
>
<div class="d-flex align-center ga-4">
<v-avatar color="secondary" size="44" variant="flat">
<span class="text-h6"></span>
</v-avatar>
<div>
<div class="text-subtitle-1 font-weight-bold">訊息中心</div>
<div class="text-body-2 font-weight-bold text-on-secondary">12 筆未讀</div>
</div>
</div>
<div class="text-body-2 font-weight-medium">查看全部 </div>
</v-card> </v-card>
<section class="d-flex flex-column pb-4"> <v-card class="pa-4 mt-4" @click="handleMessageCenter">
<div class="d-flex align-center ga-2 text-h6 font-weight-bold">🚀 快速存取</div> <v-card-title class="mb-4"> 訊息中心 </v-card-title>
<v-row class="mt-2" density="compact"> <v-card-text class="text-body-large text-secondary">
<v-col v-for="item in pageModel.quickItems" :key="item.title" cols="6" md="2" sm="4"> {{ Math.floor(Math.random() * 10) }} 筆未讀
</v-card-text>
</v-card>
<v-card variant="flat" border="thin primary" class="pa-4 mt-4">
<v-row density="compact" align="center">
<v-card-title> 快速存取 </v-card-title>
<v-col v-for="item in pageModel.quickItems" :key="item.title">
<v-card <v-card
class="d-flex flex-column align-center ga-2 text-center py-4 px-2 quick-item" class="d-flex flex-column align-center ga-1 text-center py-3 px-2"
variant="outlined" color="primary-variant"
variant="tonal"
@click="handleQuick(item)" @click="handleQuick(item)"
> >
<div class="text-h5">{{ item.icon }}</div> <div class="text-h5">{{ item.icon }}</div>
<div class="text-body-2 font-weight-medium">{{ item.title }}</div> <div class="text-body-medium font-weight-medium">{{ item.title }}</div>
</v-card> </v-card>
</v-col> </v-col>
</v-row> </v-row>
</section> </v-card>
</div> </v-container>
<v-dialog <v-dialog v-model="isNewsDialogOpen" max-width="640">
v-model="isNewsDialogOpen"
max-width="640"
>
<v-card v-if="selectedNews"> <v-card v-if="selectedNews">
<v-card-title class="text-h6 font-weight-bold bg-primary-variant pa-4"> <v-card-title class="text-h6 font-weight-bold bg-primary-variant pa-4">
{{ selectedNews.title }} {{ selectedNews.title }}
</v-card-title> </v-card-title>
<v-card-subtitle class="text-body-2 pt-4 text-medium-emphasis"> <v-card-subtitle class="text-body-2 pt-4 text-medium-emphasis">
{{ selectedNews.month }} {{ selectedNews.date }} · {{ selectedNews.month }} {{ selectedNews.date }} · {{ selectedNews.dept }} ·
{{ selectedNews.dept }} · {{ selectedNews.views }} 次瀏覽 {{ selectedNews.views }} 次瀏覽
</v-card-subtitle> </v-card-subtitle>
<v-card-text class="pt-4"> <v-card-text class="pt-4">
{{ selectedNews.desc }} {{ selectedNews.desc }}
</v-card-text> </v-card-text>
<v-card-actions class="justify-end"> <v-card-actions class="justify-end">
<v-btn color="primary" variant="text" @click="isNewsDialogOpen = false"> <v-btn color="primary" variant="text" @click="isNewsDialogOpen = false"> 關閉 </v-btn>
關閉
</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-dialog> </v-dialog>
</v-container> </v-sheet>
</template> </template>
<style scoped> <style scoped></style>
.news-item {
cursor: pointer;
transition:
transform 0.2s ease,
box-shadow 0.2s ease;
}
.news-item:hover {
transform: translateY(-2px);
box-shadow: 0 10px 24px rgba(var(--v-theme-on-surface), 0.12);
}
.news-badge {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: rgb(var(--v-theme-primary));
color: rgb(var(--v-theme-on-primary));
border-radius: 12px;
padding: 10px 6px;
min-height: 64px;
min-width: 64px;
}
.news-badge-date {
font-size: 20px;
font-weight: 700;
line-height: 1;
}
.news-badge-month {
font-size: 12px;
margin-top: 4px;
}
.quick-item {
display: flex;
cursor: pointer;
transition:
transform 0.2s ease,
box-shadow 0.2s ease;
}
.quick-item:hover {
transform: translateY(-2px);
box-shadow: 0 10px 24px rgba(var(--v-theme-on-surface), 0.12);
}
</style>