Files
his/openhis-ui-vue3/src/views/index.vue

675 lines
14 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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="dashboard-container">
<!-- 顶部导航栏 -->
<header class="header">
<div class="logo">
<span class="logo-text">医院信息管理系统</span>
</div>
<div class="header-right">
<div class="notification-badge">
<i class="header-icon">🔔</i>
<span class="badge">2</span>
</div>
<i class="header-icon"></i>
<div class="user-info">
<span class="user-avatar">👤</span>
<span>用户</span>
</div>
</div>
</header>
<!-- 主体内容 -->
<div class="main-content">
<!-- 左侧导航栏 -->
<nav class="sidebar">
<div class="menu-item active">
<span class="menu-icon">📊</span>
<span>仪表盘</span>
</div>
<div class="menu-item">
<span class="menu-icon">👥</span>
<span>患者管理</span>
</div>
<div class="menu-item">
<span class="menu-icon">💉</span>
<span>预约管理</span>
</div>
<div class="menu-item">
<span class="menu-icon">🏥</span>
<span>门诊管理</span>
</div>
<div class="menu-item">
<span class="menu-icon"></span>
<span>住院管理</span>
</div>
<div class="menu-item">
<span class="menu-icon">💊</span>
<span>药房管理</span>
</div>
<div class="menu-item">
<span class="menu-icon">📋</span>
<span>报表统计</span>
</div>
<div class="menu-item">
<span class="menu-icon"></span>
<span>系统设置</span>
</div>
</nav>
<!-- 主内容区 -->
<div class="content-wrapper">
<div class="awaitingBtn">
<el-button @click="awaitingMedicineBtn">效期预警 <span>{{ total }}</span></el-button>
</div>
<h1 class="section-title">仪表盘</h1>
<!-- 关键指标卡片 -->
<div class="dashboard-grid">
<div class="card">
<div class="card-title">今日预约量</div>
<div class="card-value">126</div>
<div class="card-stats">
<span class="stats-icon"></span>
<span>12% 较昨日</span>
</div>
</div>
<div class="card">
<div class="card-title">门诊量统计</div>
<div class="card-value">342</div>
<div class="card-stats">
<span class="stats-icon"></span>
<span>8% 较上周</span>
</div>
</div>
<div class="card">
<div class="card-title">住院患者数</div>
<div class="card-value">78</div>
<div class="card-stats down">
<span class="stats-icon"></span>
<span>5% 较上周</span>
</div>
</div>
<div class="card">
<div class="card-title">药品库存预警</div>
<div class="card-value">8</div>
<div class="card-stats">
<span class="stats-icon">!</span>
<span>需要立即处理</span>
</div>
</div>
</div>
<!-- 图表展示区 -->
<div class="chart-container">
<canvas id="statsChart"></canvas>
</div>
<!-- 重要通知和待办事项 -->
<div class="bottom-content">
<div class="notification-container">
<div class="notification-title">重要通知</div>
<ul class="notification-list">
<li class="notification-item">系统将于周六凌晨2:00进行维护升级</li>
<li class="notification-item">新的门诊排班系统已上线请尽快熟悉</li>
<li class="notification-item">三季度医疗质量分析报告已发布</li>
</ul>
</div>
<div class="todo-container">
<div class="todo-title">待办事项</div>
<ul class="todo-list">
<li class="todo-item">
<span>未完成预约</span>
<span class="todo-count">12</span>
</li>
<li class="todo-item">
<span>待处理检查结果</span>
<span class="todo-count">7</span>
</li>
<li class="todo-item">
<span>待开处方</span>
<span class="todo-count">3</span>
</li>
</ul>
<button class="btn btn-primary">查看详情</button>
</div>
</div>
<!-- 患者列表 -->
<h2 class="section-title">最近患者</h2>
<div class="table-container">
<table>
<thead>
<tr>
<th>患者姓名</th>
<th>病历号</th>
<th>年龄</th>
<th>最后就诊时间</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>张明</td>
<td>HN2023001</td>
<td>45</td>
<td>2023-10-20 09:30</td>
<td><span style="color: #67c23a;">已完成</span></td>
<td>
<button class="btn btn-outline">详情</button>
</td>
</tr>
<tr>
<td>李红</td>
<td>HN2023002</td>
<td>32</td>
<td>2023-10-20 10:15</td>
<td><span style="color: #ff9800;">待检查</span></td>
<td>
<button class="btn btn-outline">详情</button>
</td>
</tr>
<tr>
<td>王建军</td>
<td>HN2023003</td>
<td>68</td>
<td>2023-10-19 14:20</td>
<td><span style="color: #d45d79;">住院中</span></td>
<td>
<button class="btn btn-outline">详情</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</template>
<script setup name="Index">
import { ref, onMounted, onActivated } from 'vue';
import { useRouter } from 'vue-router';
import Chart from 'chart.js/auto';
import {
getExpirationWarning,
} from "./medicationmanagement/statisticalManagement/statisticalManagent";
const router = useRouter();
const total = ref(0);
function awaitingMedicineBtn() {
router.push({ path: '/medicationmanagement/statisticalManagement/earlyWarning' });
}
function getExpirationWarningCount() {
getExpirationWarning({ pageNo: 1, pageSize: 10 }).then((res) => {
total.value = res.data.total || 0;
}).catch((err) => {
console.error('获取效期预警数量失败:', err);
total.value = 0;
});
}
let chartInstance = null;
onActivated(() => {
getExpirationWarningCount();
})
onMounted(() => {
getExpirationWarningCount();
const ctx = document.getElementById('statsChart');
if (!ctx) return;
// 销毁已有实例
if (chartInstance) {
chartInstance.destroy();
}
// 模拟数据近7天门诊量与预约量
const labels = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
const outpatientData = [310, 335, 305, 345, 370, 270, 210]; // 门诊量(柱状图)
const appointmentData = [100, 120, 110, 130, 140, 90, 70]; // 预约量(折线图)
chartInstance = new Chart(ctx.getContext('2d'), {
type: 'bar',
data: {
labels: labels,
datasets: [
{
label: '门诊量',
data: outpatientData,
backgroundColor: '#91c8e5',
borderColor: '#66a8cc',
borderWidth: 1,
borderRadius: 4,
borderSkipped: false,
},
{
label: '预约量',
data: appointmentData,
type: 'line',
borderColor: '#f56c6c',
backgroundColor: 'rgba(245, 108, 108, 0.1)',
borderWidth: 2,
pointBackgroundColor: '#f56c6c',
pointBorderColor: '#fff',
pointBorderWidth: 2,
pointRadius: 4,
fill: true,
tension: 0.3,
lineTension: 0.3,
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'top',
labels: {
font: {
size: 12,
weight: 'bold'
}
}
},
tooltip: {
mode: 'index',
intersect: false,
backgroundColor: 'rgba(0, 0, 0, 0.7)',
titleFont: {
size: 13
},
bodyFont: {
size: 12
}
}
},
scales: {
x: {
grid: {
display: false
},
ticks: {
font: {
size: 11
}
}
},
y: {
beginAtZero: true,
max: 400,
stepSize: 50,
grid: {
color: 'rgba(0, 0, 0, 0.05)'
},
ticks: {
font: {
size: 11
}
}
}
}
}
});
});
</script>
<style scoped lang="scss">
.dashboard-container {
display: flex;
flex-direction: column;
height: 100vh;
background-color: #f5f7fa;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
padding: 0;
}
.header {
height: 60px;
background-color: white;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24px;
position: sticky;
top: 0;
z-index: 1000;
}
.logo {
display: flex;
align-items: center;
}
.logo-text {
font-size: 18px;
font-weight: 600;
color: #166773;
}
.header-right {
display: flex;
align-items: center;
gap: 16px;
}
.notification-badge {
position: relative;
cursor: pointer;
}
.header-icon {
font-size: 20px;
cursor: pointer;
padding: 8px;
border-radius: 4px;
transition: background-color 0.3s;
}
.header-icon:hover {
background-color: #f5f7fa;
}
.badge {
position: absolute;
top: 0;
right: 0;
background-color: #ff4d4f;
color: white;
font-size: 12px;
padding: 2px 6px;
border-radius: 10px;
min-width: 16px;
text-align: center;
}
.user-info {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 12px;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
.user-info:hover {
background-color: #f5f7fa;
}
.user-avatar {
font-size: 20px;
}
.main-content {
display: flex;
flex: 1;
overflow: hidden;
}
.sidebar {
width: 200px;
background-color: white;
box-shadow: 2px 0 4px rgba(0, 0, 0, 0.1);
overflow-y: auto;
}
.menu-item {
display: flex;
align-items: center;
padding: 16px 24px;
cursor: pointer;
transition: all 0.3s;
border-left: 3px solid transparent;
}
.menu-item:hover {
background-color: #f0f9ff;
}
.menu-item.active {
background-color: #e6f7ff;
border-left-color: #1890ff;
color: #1890ff;
font-weight: 500;
}
.menu-icon {
margin-right: 12px;
font-size: 18px;
}
.content-wrapper {
flex: 1;
padding: 20px;
overflow-y: auto;
background-color: #f5f7fa;
}
.awaitingBtn {
margin-bottom: 20px;
.el-button{
border: 1px #166773 solid;
span{
color: red;
margin-left: 5px;
}
}
.el-button:hover{
border: 1px #166773 solid;
color: #166773;
span{
color: red;
margin-left: 5px;
}
}
}
.section-title {
font-size: 24px;
margin-bottom: 20px;
color: #333;
font-weight: 600;
}
.card {
background-color: #fff;
border-radius: 8px;
padding: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
}
.card:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
}
.card-title {
font-size: 14px;
color: #606266;
margin-bottom: 12px;
}
.card-value {
font-size: 32px;
font-weight: 600;
color: #303133;
margin-bottom: 8px;
}
.card-stats {
display: flex;
align-items: center;
font-size: 12px;
color: #67c23a;
}
.card-stats.down {
color: #f56c6c;
}
.stats-icon {
margin-right: 4px;
}
.dashboard-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.chart-container {
background-color: #fff;
border-radius: 8px;
padding: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
margin-bottom: 30px;
height: 300px;
canvas {
width: 100% !important;
height: 100% !important;
}
}
.bottom-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-bottom: 30px;
}
.notification-container,
.todo-container {
background-color: #fff;
border-radius: 8px;
padding: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
.notification-title,
.todo-title {
font-size: 18px;
font-weight: 600;
color: #303133;
margin-bottom: 16px;
}
.notification-list {
list-style: none;
padding: 0;
margin: 0;
}
.notification-item {
padding: 12px 0;
border-bottom: 1px solid #ebeef5;
&:last-child {
border-bottom: none;
}
}
.todo-list {
list-style: none;
padding: 0;
margin: 0;
margin-bottom: 20px;
}
.todo-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 0;
border-bottom: 1px solid #ebeef5;
&:last-child {
border-bottom: none;
}
}
.todo-count {
color: #606266;
font-size: 14px;
}
.table-container {
background-color: #fff;
border-radius: 8px;
padding: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #ebeef5;
}
th {
background-color: #f5f7fa;
font-weight: 600;
color: #303133;
}
tr:last-child td {
border-bottom: none;
}
.btn {
padding: 6px 12px;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
transition: all 0.3s ease;
border: none;
outline: none;
}
.btn-primary {
background-color: #1890ff;
color: #fff;
}
.btn-primary:hover {
background-color: #40a9ff;
}
.btn-outline {
background-color: transparent;
border: 1px solid #dcdfe6;
color: #606266;
}
.btn-outline:hover {
border-color: #c6e2ff;
color: #40a9ff;
background-color: #ecf5ff;
}
@media (max-width: 768px) {
.bottom-content {
grid-template-columns: 1fr;
}
.dashboard-grid {
grid-template-columns: 1fr;
}
}
</style>