Files
gpf_pet_hospital/frontend/src/pages/WelcomePage.vue

426 lines
10 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="welcome-page">
<div class="welcome-container">
<div class="welcome-header">
<div class="logo-section">
<div class="logo">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 2L2 7l10 5 10-5-10-5z"/>
<path d="M2 17l10 5 10-5"/>
<path d="M2 12l10 5 10-5"/>
</svg>
</div>
<h1>欢迎回来{{ auth.user?.username || '用户' }}</h1>
<p class="subtitle">{{ isDoctor ? '医生工作台' : '爱维宠物医院竭诚为您服务' }}</p>
</div>
</div>
<div class="quick-actions">
<h3>快速入口</h3>
<div class="action-grid">
<!-- 顾客专属 -->
<template v-if="isCustomer">
<div class="action-card" @click="goTo('/pets')">
<div class="action-icon">🐾</div>
<div class="action-text">
<h4>我的宠物</h4>
<p>管理您的爱宠信息</p>
</div>
</div>
<div class="action-card" @click="goTo('/appointments')">
<div class="action-icon">📅</div>
<div class="action-text">
<h4>预约挂号</h4>
<p>在线预约门诊服务</p>
</div>
</div>
<div class="action-card" @click="goTo('/reports')">
<div class="action-icon">📋</div>
<div class="action-text">
<h4>检查报告</h4>
<p>查看宠物检查报告</p>
</div>
</div>
<div class="action-card" @click="goTo('/orders')">
<div class="action-icon">💊</div>
<div class="action-text">
<h4>我的订单</h4>
<p>查看购药订单记录</p>
</div>
</div>
</template>
<!-- 医生专属 -->
<template v-if="isDoctor">
<div class="action-card" @click="goTo('/admin/visits')">
<div class="action-icon">🏥</div>
<div class="action-text">
<h4>就诊记录</h4>
<p>管理就诊信息</p>
</div>
</div>
<div class="action-card" @click="goTo('/admin/records')">
<div class="action-icon">📖</div>
<div class="action-text">
<h4>病历管理</h4>
<p>管理宠物病历</p>
</div>
</div>
<div class="action-card" @click="goTo('/admin/prescriptions')">
<div class="action-icon">💉</div>
<div class="action-text">
<h4>处方管理</h4>
<p>开具和管理处方</p>
</div>
</div>
<div class="action-card" @click="goTo('/admin/reports')">
<div class="action-icon">📋</div>
<div class="action-text">
<h4>诊断报告</h4>
<p>管理检查报告</p>
</div>
</div>
</template>
</div>
</div>
<div class="notices-section" v-if="notices.length > 0">
<h3>📢 最新公告</h3>
<div class="notice-list">
<div
v-for="notice in notices"
:key="notice.id"
class="notice-item"
@click="showNoticeDetail(notice)"
>
<span class="notice-top" v-if="notice.isTop === 1">置顶</span>
<span class="notice-title">{{ notice.title }}</span>
<span class="notice-date">{{ formatDate(notice.createTime) }}</span>
</div>
</div>
</div>
<div class="tips-section">
<div class="tip-card">
<h4>💡 {{ isDoctor ? '工作提示' : '温馨提示' }}</h4>
<ul v-if="isDoctor">
<li>及时查看和处理新的预约申请</li>
<li>认真填写病历和处方信息</li>
<li>如有紧急情况请及时上报</li>
</ul>
<ul v-else>
<li>定期为爱宠进行体检关注健康状况</li>
<li>提前预约可避免排队等待</li>
<li>如有紧急情况请直接拨打医院电话</li>
</ul>
</div>
<div class="contact-card">
<h4>📞 联系我们</h4>
<p>电话400-123-4567</p>
<p>地址XX市XX区XX路XX号</p>
<p>营业时间09:00 - 21:00</p>
</div>
</div>
</div>
<t-dialog
v-model:visible="dialogVisible"
:header="selectedNotice?.title || '公告详情'"
width="600"
>
<div class="notice-content">
<div class="notice-meta">
<span v-if="selectedNotice?.isTop === 1" class="top-badge">置顶</span>
<span class="publish-time">发布时间{{ formatDate(selectedNotice?.createTime) }}</span>
</div>
<div class="notice-body">{{ selectedNotice?.content }}</div>
</div>
</t-dialog>
</div>
</template>
<script setup lang="ts">
import { useRouter } from 'vue-router';
import { useAuthStore } from '../store/auth';
import { ref, onMounted, computed } from 'vue';
import { api } from '../api';
const router = useRouter();
const auth = useAuthStore();
const notices = ref<any[]>([]);
const dialogVisible = ref(false);
const selectedNotice = ref<any>(null);
const isCustomer = computed(() => auth.user?.role === 'CUSTOMER');
const isDoctor = computed(() => auth.user?.role === 'DOCTOR');
const goTo = (path: string) => {
router.push(path);
};
const formatDate = (dateStr: string | null | undefined) => {
if (!dateStr) return '-';
const date = new Date(dateStr);
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
};
const loadNotices = async () => {
try {
const res = await api.notices({ page: 1, size: 5 });
if (res.code === 0 && res.data?.records) {
const list = res.data.records.filter((n: any) => n.status === 1);
list.sort((a: any, b: any) => {
if (a.isTop !== b.isTop) return b.isTop - a.isTop;
return new Date(b.createTime).getTime() - new Date(a.createTime).getTime();
});
notices.value = list.slice(0, 5);
}
} catch (error) {
console.error('加载公告失败:', error);
}
};
const showNoticeDetail = (notice: any) => {
selectedNotice.value = notice;
dialogVisible.value = true;
};
onMounted(() => {
loadNotices();
});
</script>
<style scoped>
.welcome-page {
padding: 24px;
min-height: calc(100vh - 64px);
background: linear-gradient(135deg, #f0fdf4 0%, #ecfdf5 100%);
}
.welcome-container {
max-width: 1200px;
margin: 0 auto;
}
.welcome-header {
text-align: center;
padding: 40px 0;
}
.logo-section .logo {
width: 64px;
height: 64px;
margin: 0 auto 20px;
background: linear-gradient(135deg, #0d9488, #14b8a6);
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
color: white;
}
.logo svg {
width: 32px;
height: 32px;
}
.welcome-header h1 {
font-size: 28px;
font-weight: 700;
color: #1f2937;
margin: 0 0 8px;
}
.subtitle {
font-size: 16px;
color: #6b7280;
}
.quick-actions {
margin-bottom: 32px;
}
.quick-actions h3,
.notices-section h3 {
font-size: 20px;
font-weight: 600;
color: #374151;
margin-bottom: 16px;
}
.action-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 16px;
}
.action-card {
background: white;
border-radius: 12px;
padding: 24px;
display: flex;
align-items: center;
gap: 16px;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.action-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.action-icon {
font-size: 32px;
width: 56px;
height: 56px;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #0d9488, #14b8a6);
border-radius: 12px;
}
.action-text h4 {
font-size: 16px;
font-weight: 600;
color: #1f2937;
margin: 0 0 4px;
}
.action-text p {
font-size: 14px;
color: #6b7280;
margin: 0;
}
.notices-section {
margin-bottom: 32px;
}
.notice-list {
background: white;
border-radius: 12px;
padding: 16px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.notice-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
cursor: pointer;
border-radius: 8px;
transition: background 0.2s;
}
.notice-item:hover {
background: #f3f4f6;
}
.notice-item:not(:last-child) {
border-bottom: 1px solid #f3f4f6;
}
.notice-top {
background: linear-gradient(135deg, #ef4444, #f87171);
color: white;
font-size: 12px;
padding: 2px 8px;
border-radius: 4px;
font-weight: 500;
flex-shrink: 0;
}
.notice-title {
flex: 1;
font-size: 15px;
color: #1f2937;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.notice-date {
font-size: 13px;
color: #9ca3af;
flex-shrink: 0;
}
.tips-section {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 16px;
}
.tip-card,
.contact-card {
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.tip-card h4,
.contact-card h4 {
font-size: 16px;
font-weight: 600;
color: #1f2937;
margin: 0 0 12px;
}
.tip-card ul {
margin: 0;
padding-left: 20px;
}
.tip-card li {
font-size: 14px;
color: #4b5563;
margin-bottom: 8px;
}
.contact-card p {
font-size: 14px;
color: #4b5563;
margin: 0 0 8px;
}
.notice-content {
padding: 8px 0;
}
.notice-meta {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
padding-bottom: 16px;
border-bottom: 1px solid #e5e7eb;
}
.top-badge {
background: linear-gradient(135deg, #ef4444, #f87171);
color: white;
font-size: 12px;
padding: 2px 10px;
border-radius: 4px;
font-weight: 500;
}
.publish-time {
font-size: 13px;
color: #6b7280;
}
.notice-body {
font-size: 15px;
line-height: 1.8;
color: #374151;
white-space: pre-wrap;
}
</style>