Files
his/openhis-ui-vue3/src/views/index.vue
2026-01-16 16:32:36 +08:00

890 lines
26 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="home-container">
<!-- 顶部欢迎区域 -->
<div class="welcome-section">
<div class="welcome-content">
<div class="greeting">
<h1>{{ getGreeting() }}{{ userStore.nickName || userStore.name }}</h1>
<p>欢迎使用{{ userStore.hospitalName || '医院' }}管理系统</p>
</div>
<div class="role-badge" v-if="userStore.roles.length > 0">
<el-tag :type="getRoleTagType(userStore.roles[0])" size="large">
{{ getRoleName(userStore.roles[0]) }}
</el-tag>
</div>
</div>
</div>
<!-- 关键数据统计 -->
<div class="stats-grid">
<div
v-for="stat in currentStats"
:key="stat.key"
class="stat-card"
:class="`stat-${stat.type}`"
@click="handleStatClick(stat)"
>
<div class="stat-icon">
<el-icon :size="36" :color="stat.iconColor">
<component :is="stat.icon" />
</el-icon>
</div>
<div class="stat-content">
<div class="stat-value">{{ stat.value }}</div>
<div class="stat-label">{{ stat.label }}</div>
<div class="stat-trend" v-if="stat.trend">
<span :class="stat.trend > 0 ? 'trend-up' : 'trend-down'">
{{ stat.trend > 0 ? '↑' : '↓' }} {{ Math.abs(stat.trend) }}%
</span>
<span class="trend-label">较昨日</span>
</div>
</div>
</div>
</div>
<!-- 快捷功能入口 -->
<div class="quick-access-section">
<div class="section-header">
<h3>快捷功能</h3>
<el-button text type="primary" @click="showAllFunctions">查看全部</el-button>
</div>
<div class="quick-access-grid">
<div
v-for="func in quickAccess"
:key="func.key"
class="quick-access-card"
@click="handleQuickAccess(func)"
>
<div class="quick-icon">
<el-icon :size="28" :color="func.iconColor">
<component :is="func.icon" />
</el-icon>
</div>
<div class="quick-label">{{ func.label }}</div>
</div>
</div>
</div>
<!-- 待办事项 -->
<div class="todo-section" v-if="todoList.length > 0">
<div class="section-header">
<h3>待办事项</h3>
<el-badge :value="todoList.length" class="todo-badge">
<el-button text type="primary" @click="showAllTodos">查看全部</el-button>
</el-badge>
</div>
<div class="todo-list">
<div
v-for="todo in todoList.slice(0, 5)"
:key="todo.id"
class="todo-item"
:class="`priority-${todo.priority}`"
@click="handleTodoClick(todo)"
>
<div class="todo-icon">
<el-icon :size="20">
<component :is="todo.icon" />
</el-icon>
</div>
<div class="todo-content">
<div class="todo-title">{{ todo.title }}</div>
<div class="todo-desc">{{ todo.desc }}</div>
</div>
<div class="todo-time">{{ todo.time }}</div>
</div>
</div>
</div>
<!-- 今日日程 -->
<div class="schedule-section">
<div class="section-header">
<h3>今日日程</h3>
<el-button text type="primary" @click="showSchedule">管理日程</el-button>
</div>
<div class="schedule-list">
<div
v-for="item in scheduleList"
:key="item.id"
class="schedule-item"
>
<div class="schedule-time">{{ item.time }}</div>
<div class="schedule-content">
<div class="schedule-title">{{ item.title }}</div>
<div class="schedule-location">
<el-icon><Location /></el-icon>
<span>{{ item.location }}</span>
</div>
</div>
<el-tag :type="item.type" size="small">{{ item.tag }}</el-tag>
</div>
</div>
</div>
</div>
</template>
<script setup name="Home">
import { ref, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import useUserStore from '@/store/modules/user'
import { getHomeStatistics } from '@/api/home'
import {
User,
Document,
Calendar,
Money,
Warning,
TrendCharts,
Monitor,
Clock,
ChatDotRound,
Files,
Box,
Operation,
Location,
Notification,
DataLine,
ShoppingCart,
Wallet,
Van,
Bell,
Setting,
Search
} from '@element-plus/icons-vue'
const userStore = useUserStore()
const router = useRouter()
// 统计数据(从后端获取)
const statisticsData = ref({
totalPatients: 0,
yesterdayPatients: 0,
patientTrend: 0,
todayRevenue: '¥ 0',
yesterdayRevenue: '¥ 0',
revenueTrend: 0,
todayAppointments: 0,
yesterdayAppointments: 0,
appointmentTrend: 0,
pendingApprovals: 0
})
// 不同角色的统计数据配置
const roleStatsConfig = {
admin: [
{ key: 'totalPatients', label: '在院患者', icon: User, type: 'primary', iconColor: '#409eff' },
{ key: 'todayRevenue', label: '今日收入', icon: Money, type: 'success', iconColor: '#67c23a' },
{ key: 'appointments', label: '今日预约', icon: Calendar, type: 'warning', iconColor: '#e6a23c' },
{ key: 'pendingApprovals', label: '待审核', icon: Document, type: 'danger', iconColor: '#f56c6c' }
],
doctor: [
{ key: 'myPatients', label: '我的患者', icon: User, type: 'primary', iconColor: '#409eff' },
{ key: 'todayAppointments', label: '今日门诊', icon: Calendar, type: 'success', iconColor: '#67c23a' },
{ key: 'pendingRecords', label: '待写病历', icon: Document, type: 'warning', iconColor: '#e6a23c' },
{ key: 'prescriptions', label: '今日处方', icon: Box, type: 'info', iconColor: '#909399' }
],
nurse: [
{ key: 'wardPatients', label: '病房患者', icon: User, type: 'primary', iconColor: '#409eff' },
{ key: 'todayTreatments', label: '今日治疗', icon: Operation, type: 'success', iconColor: '#67c23a' },
{ key: 'vitalSigns', label: '待测体征', icon: Monitor, type: 'warning', iconColor: '#e6a23c' },
{ key: 'drugDistribution', label: '发药次数', icon: Box, type: 'info', iconColor: '#909399' }
],
pharmacist: [
{ key: 'todayPrescriptions', label: '今日处方', icon: Box, type: 'primary', iconColor: '#409eff' },
{ key: 'pendingReview', label: '待审核', icon: Document, type: 'warning', iconColor: '#e6a23c' },
{ key: 'outOfStock', label: '缺货药品', icon: Warning, type: 'danger', iconColor: '#f56c6c' },
{ key: 'nearExpiry', label: '近效期', icon: Clock, type: 'info', iconColor: '#909399' }
],
cashier: [
{ key: 'todayPayments', label: '今日缴费', icon: Money, type: 'primary', iconColor: '#409eff' },
{ key: 'refundRequests', label: '退费申请', icon: Document, type: 'warning', iconColor: '#e6a23c' },
{ key: 'pendingInvoices', label: '待开发票', icon: Files, type: 'info', iconColor: '#909399' },
{ key: 'insuranceClaims', label: '医保结算', icon: Wallet, type: 'success', iconColor: '#67c23a' }
]
}
// 不同角色的快捷功能配置
const roleQuickAccessConfig = {
admin: [
{ key: 'patient', label: '患者管理', icon: User, iconColor: '#409eff', route: '/patientmanagement' },
{ key: 'appointment', label: '预约管理', icon: Calendar, iconColor: '#67c23a', route: '/appoinmentmanage' },
{ key: 'doctor', label: '医生管理', icon: User, iconColor: '#e6a23c', route: '/doctorstation' },
{ key: 'surgery', label: '手术管理', icon: Operation, iconColor: '#f56c6c', route: '/surgerymanage' },
{ key: 'drug', label: '药品管理', icon: Box, iconColor: '#909399', route: '/pharmacymanagement' },
{ key: 'statistic', label: '数据统计', icon: TrendCharts, iconColor: '#409eff', route: '/monitor' },
{ key: 'invoice', label: '发票管理', icon: Files, iconColor: '#67c23a', route: '/basicmanage/InvoiceManagement' },
{ key: 'system', label: '系统设置', icon: Setting, iconColor: '#909399', route: '/system' }
],
doctor: [
{ key: 'outpatient', label: '门诊接诊', icon: ChatDotRound, iconColor: '#409eff', route: '/doctorstation' },
{ key: 'emr', label: '病历管理', icon: Document, iconColor: '#67c23a', route: '/doctorstation/doctorphrase' },
{ key: 'prescription', label: '开立处方', icon: Box, iconColor: '#e6a23c', route: '/clinicmanagement/ePrescribing' },
{ key: 'history', label: '历史处方', icon: Clock, iconColor: '#f56c6c', route: '/clinicmanagement/historicalPrescription' },
{ key: 'schedule', label: '排班管理', icon: Calendar, iconColor: '#909399', route: '/appoinmentmanage/deptManage' },
{ key: 'inquiry', label: '患者查询', icon: Search, iconColor: '#409eff', route: '/patientmanagement' }
],
nurse: [
{ key: 'ward', label: '病房管理', icon: User, iconColor: '#409eff', route: '/inpatientNurse/inpatientNurseStation' },
{ key: 'execution', label: '医嘱执行', icon: Operation, iconColor: '#67c23a', route: '/inpatientNurse/medicalOrderExecution' },
{ key: 'proofread', label: '医嘱核对', icon: Document, iconColor: '#e6a23c', route: '/inpatientNurse/medicalOrderProofread' },
{ key: 'drugCollect', label: '领药管理', icon: Box, iconColor: '#f56c6c', route: '/inpatientNurse/medicineCollect' },
{ key: 'tpr', label: '体温单', icon: Monitor, iconColor: '#909399', route: '/inpatientNurse/tprsheet' },
{ key: 'nursing', label: '护理记录', icon: ChatDotRound, iconColor: '#409eff', route: '/inpatientNurse/nursingRecord' }
],
pharmacist: [
{ key: 'dispensing', label: '发药管理', icon: Box, iconColor: '#409eff', route: '/pharmacymanagement' },
{ key: 'prescription', label: '处方审核', icon: Document, iconColor: '#67c23a', route: '/pharmacymanagement' },
{ key: 'inventory', label: '库存管理', icon: Van, iconColor: '#e6a23c', route: '/medicineStorage' },
{ key: 'purchase', label: '采购管理', icon: ShoppingCart, iconColor: '#f56c6c', route: '/medicineStorage' },
{ key: 'warning', label: '效期预警', icon: Warning, iconColor: '#f56c6c', route: '/medicationmanagement/statisticalManagement/statisticalManagement' },
{ key: 'statistics', label: '用药统计', icon: DataLine, iconColor: '#909399', route: '/monitor' }
],
cashier: [
{ key: 'registration', label: '挂号收费', icon: Money, iconColor: '#409eff', route: '/charge/outpatientregistration' },
{ key: 'clinicCharge', label: '门诊收费', icon: Wallet, iconColor: '#67c23a', route: '/charge/cliniccharge' },
{ key: 'refund', label: '退费管理', icon: Document, iconColor: '#e6a23c', route: '/charge/clinicrefund' },
{ key: 'invoice', label: '发票打印', icon: Files, iconColor: '#f56c6c', route: '/basicmanage/InvoiceManagement' },
{ key: 'record', label: '收费记录', icon: Clock, iconColor: '#909399', route: '/charge/clinicRecord' },
{ key: 'insurance', label: '医保结算', icon: Bell, iconColor: '#409eff', route: '/ybmanagement' }
]
}
// 待办事项
const todoList = ref([
{ id: 1, title: '审核处方申请', desc: '张医生提交的5条处方待审核', priority: 'high', icon: Document, time: '10分钟前' },
{ id: 2, title: '确认患者入院', desc: '李某某45岁已办理入院', priority: 'medium', icon: User, time: '30分钟前' },
{ id: 3, title: '处理投诉反馈', desc: '患者家属对服务态度的投诉', priority: 'high', icon: ChatDotRound, time: '1小时前' },
{ id: 4, title: '药品效期预警', desc: '阿莫西林等3种药品即将过期', priority: 'low', icon: Warning, time: '2小时前' },
{ id: 5, title: '月度报表审核', desc: '11月份门诊收入报表待审核', priority: 'medium', icon: Files, time: '3小时前' }
])
// 今日日程
const scheduleList = ref([
{ id: 1, time: '09:00', title: '科室晨会', location: '第一会议室', type: 'info', tag: '日常' },
{ id: 2, time: '10:30', title: '病例讨论', location: '第二会议室', type: 'primary', tag: '会议' },
{ id: 3, time: '14:00', title: '专家查房', location: '住院部3楼', type: 'warning', tag: '重要' },
{ id: 4, time: '16:00', title: '新药培训', location: '培训中心', type: 'success', tag: '培训' }
])
// 获取问候语
const getGreeting = () => {
const hour = new Date().getHours()
if (hour < 6) return '夜深了'
if (hour < 9) return '早上好'
if (hour < 12) return '上午好'
if (hour < 14) return '中午好'
if (hour < 17) return '下午好'
if (hour < 19) return '傍晚好'
return '晚上好'
}
// 获取角色名称
const getRoleName = (role) => {
const roleMap = {
admin: '管理员',
doctor: '医生',
nurse: '护士',
pharmacist: '药剂师',
cashier: '收费员'
}
return roleMap[role] || role
}
// 获取角色标签类型
const getRoleTagType = (role) => {
const typeMap = {
admin: 'danger',
doctor: 'primary',
nurse: 'success',
pharmacist: 'warning',
cashier: 'info'
}
return typeMap[role] || ''
}
// 根据角色获取当前统计数据
const currentStats = computed(() => {
const role = userStore.roles[0] || 'admin'
const baseConfig = roleStatsConfig[role] || roleStatsConfig.admin
// 合并配置和实际数据
return baseConfig.map(stat => {
const statWith = { ...stat }
// 根据不同的 key 获取对应的值
switch (stat.key) {
case 'totalPatients':
statWith.value = statisticsData.value.totalPatients
statWith.trend = statisticsData.value.patientTrend
break
case 'todayRevenue':
statWith.value = statisticsData.value.todayRevenue
statWith.trend = statisticsData.value.revenueTrend
break
case 'appointments':
statWith.value = statisticsData.value.todayAppointments
statWith.trend = statisticsData.value.appointmentTrend
break
case 'pendingApprovals':
statWith.value = statisticsData.value.pendingApprovals
break
case 'myPatients':
statWith.value = statisticsData.value.totalPatients
statWith.trend = statisticsData.value.patientTrend
break
case 'todayAppointments':
statWith.value = statisticsData.value.todayAppointments
statWith.trend = statisticsData.value.appointmentTrend
break
case 'pendingRecords':
statWith.value = statisticsData.value.pendingApprovals
break
case 'prescriptions':
statWith.value = statisticsData.value.todayAppointments
statWith.trend = statisticsData.value.appointmentTrend
break
case 'wardPatients':
statWith.value = statisticsData.value.totalPatients
statWith.trend = statisticsData.value.patientTrend
break
case 'todayTreatments':
statWith.value = statisticsData.value.todayAppointments
statWith.trend = statisticsData.value.appointmentTrend
break
case 'vitalSigns':
statWith.value = statisticsData.value.pendingApprovals
break
case 'drugDistribution':
statWith.value = statisticsData.value.todayAppointments
statWith.trend = statisticsData.value.appointmentTrend
break
case 'todayPrescriptions':
statWith.value = statisticsData.value.todayAppointments
statWith.trend = statisticsData.value.appointmentTrend
break
case 'pendingReview':
statWith.value = statisticsData.value.pendingApprovals
break
case 'outOfStock':
statWith.value = statisticsData.value.pendingApprovals
break
case 'nearExpiry':
statWith.value = statisticsData.value.pendingApprovals
break
case 'todayPayments':
statWith.value = statisticsData.value.todayRevenue
statWith.trend = statisticsData.value.revenueTrend
break
case 'refundRequests':
statWith.value = statisticsData.value.pendingApprovals
break
case 'pendingInvoices':
statWith.value = statisticsData.value.pendingApprovals
break
case 'insuranceClaims':
statWith.value = statisticsData.value.todayAppointments
statWith.trend = statisticsData.value.appointmentTrend
break
default:
statWith.value = '0'
statWith.trend = 0
}
return statWith
})
})
// 根据角色获取快捷功能
const quickAccess = computed(() => {
const role = userStore.roles[0] || 'admin'
return roleQuickAccessConfig[role] || roleQuickAccessConfig.admin
})
// 处理统计卡片点击
const handleStatClick = (stat) => {
console.log('Stat clicked:', stat)
// 根据不同的统计项跳转到相应的详情页面
if (stat.key === 'totalPatients' || stat.key === 'myPatients' || stat.key === 'wardPatients') {
// 在院患者/我的患者/病房患者 - 跳转到患者管理页面
router.push('/patient/patientmgr')
} else if (stat.key === 'todayRevenue' || stat.key === 'todayPayments') {
// 跳转到收费页面
router.push('/charge/cliniccharge')
} else if (stat.key === 'appointments') {
// 跳转到预约管理页面
router.push('/appoinmentmanage')
} else if (stat.key === 'todayAppointments') {
// 跳转到今日门诊模块
router.push('/doctorstation/today-outpatient')
} else if (stat.key === 'pendingApprovals' || stat.key === 'pendingReview') {
// 跳转到待审核页面
router.push('/clinicmanagement/ePrescribing')
}
}
// 处理快捷功能点击
const handleQuickAccess = (func) => {
if (func.route) {
router.push(func.route)
}
}
// 处理待办事项点击
const handleTodoClick = (todo) => {
console.log('Todo clicked:', todo)
// 跳转到相应的处理页面
}
// 显示全部功能
const showAllFunctions = () => {
// 跳转到功能菜单页面
}
// 显示全部待办
const showAllTodos = () => {
// 跳转到待办事项页面
}
// 管理日程
const showSchedule = () => {
// 跳转到日程管理页面
}
// 获取统计数据
const fetchStatsData = async () => {
try {
const res = await getHomeStatistics()
if (res.data) {
statisticsData.value = res.data
console.log('统计数据:', statisticsData.value)
}
} catch (error) {
console.error('获取统计数据失败:', error)
}
}
// 获取待办事项实际应用中应该从API获取
const fetchTodoList = async () => {
// TODO: 调用API获取真实数据
console.log('Fetching todo list...')
}
// 获取日程数据实际应用中应该从API获取
const fetchScheduleList = async () => {
// TODO: 调用API获取真实数据
console.log('Fetching schedule list...')
}
onMounted(() => {
fetchStatsData()
fetchTodoList()
fetchScheduleList()
})
</script>
<style scoped lang="scss">
.home-container {
padding: 20px;
background: #f5f7fa;
min-height: calc(100vh - 120px);
}
/* 顶部欢迎区域 */
.welcome-section {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 12px;
padding: 30px;
margin-bottom: 20px;
color: white;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
.welcome-content {
display: flex;
justify-content: space-between;
align-items: center;
.greeting {
h1 {
font-size: 28px;
font-weight: 600;
margin: 0 0 8px 0;
}
p {
font-size: 16px;
opacity: 0.9;
margin: 0;
}
}
.role-badge {
:deep(.el-tag) {
font-size: 16px;
padding: 12px 24px;
height: auto;
background: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(255, 255, 255, 0.3);
color: white;
}
}
}
}
/* 统计卡片网格 */
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 16px;
margin-bottom: 20px;
.stat-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 2px 8px rgba(0, 0, 0, 0.05);
border-left: 4px solid transparent;
&:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
}
&.stat-primary {
border-left-color: #409eff;
}
&.stat-success {
border-left-color: #67c23a;
}
&.stat-warning {
border-left-color: #e6a23c;
}
&.stat-danger {
border-left-color: #f56c6c;
}
&.stat-info {
border-left-color: #909399;
}
.stat-icon {
width: 60px;
height: 60px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
background: #f5f7fa;
}
.stat-content {
flex: 1;
.stat-value {
font-size: 24px;
font-weight: 600;
color: #303133;
margin-bottom: 4px;
}
.stat-label {
font-size: 14px;
color: #909399;
margin-bottom: 8px;
}
.stat-trend {
font-size: 12px;
.trend-up {
color: #67c23a;
margin-right: 4px;
}
.trend-down {
color: #f56c6c;
margin-right: 4px;
}
.trend-label {
color: #c0c4cc;
}
}
}
}
}
/* 快捷功能区域 */
.quick-access-section {
background: white;
border-radius: 12px;
padding: 24px;
margin-bottom: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
h3 {
font-size: 18px;
font-weight: 600;
color: #303133;
margin: 0;
}
}
.quick-access-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 16px;
.quick-access-card {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 24px 16px;
border-radius: 8px;
background: #f5f7fa;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
background: #ecf5ff;
transform: translateY(-4px);
.quick-label {
color: #409eff;
}
}
.quick-icon {
margin-bottom: 12px;
}
.quick-label {
font-size: 14px;
color: #606266;
text-align: center;
transition: color 0.3s;
}
}
}
}
/* 待办事项区域 */
.todo-section {
background: white;
border-radius: 12px;
padding: 24px;
margin-bottom: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
h3 {
font-size: 18px;
font-weight: 600;
color: #303133;
margin: 0;
}
}
.todo-list {
.todo-item {
display: flex;
align-items: center;
padding: 16px;
border-radius: 8px;
margin-bottom: 12px;
background: #f5f7fa;
cursor: pointer;
transition: all 0.3s ease;
border-left: 3px solid transparent;
&:hover {
background: #ecf5ff;
}
&.priority-high {
border-left-color: #f56c6c;
}
&.priority-medium {
border-left-color: #e6a23c;
}
&.priority-low {
border-left-color: #67c23a;
}
&:last-child {
margin-bottom: 0;
}
.todo-icon {
margin-right: 12px;
color: #909399;
}
.todo-content {
flex: 1;
.todo-title {
font-size: 14px;
color: #303133;
font-weight: 500;
margin-bottom: 4px;
}
.todo-desc {
font-size: 12px;
color: #909399;
}
}
.todo-time {
font-size: 12px;
color: #c0c4cc;
}
}
}
}
/* 日程区域 */
.schedule-section {
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
h3 {
font-size: 18px;
font-weight: 600;
color: #303133;
margin: 0;
}
}
.schedule-list {
.schedule-item {
display: flex;
align-items: center;
padding: 16px;
border-radius: 8px;
margin-bottom: 12px;
background: #f5f7fa;
transition: all 0.3s ease;
&:hover {
background: #ecf5ff;
}
&:last-child {
margin-bottom: 0;
}
.schedule-time {
width: 80px;
font-size: 18px;
font-weight: 600;
color: #409eff;
}
.schedule-content {
flex: 1;
margin: 0 16px;
.schedule-title {
font-size: 14px;
color: #303133;
font-weight: 500;
margin-bottom: 4px;
}
.schedule-location {
display: flex;
align-items: center;
font-size: 12px;
color: #909399;
.el-icon {
margin-right: 4px;
}
}
}
}
}
}
/* 响应式设计 */
@media (max-width: 1200px) {
.stats-grid {
grid-template-columns: repeat(2, 1fr);
}
.quick-access-grid {
grid-template-columns: repeat(4, 1fr);
}
}
@media (max-width: 768px) {
.home-container {
padding: 12px;
}
.welcome-section {
padding: 20px;
.welcome-content {
flex-direction: column;
align-items: flex-start;
gap: 16px;
.greeting {
h1 {
font-size: 22px;
}
p {
font-size: 14px;
}
}
}
}
.stats-grid {
grid-template-columns: 1fr;
}
.quick-access-grid {
grid-template-columns: repeat(3, 1fr);
}
}
@media (max-width: 480px) {
.quick-access-grid {
grid-template-columns: repeat(2, 1fr);
}
}
</style>