index.vue 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. <template>
  2. <div class="emergency-home-page">
  3. <!-- 模块标题 -->
  4. <div class="module-header">
  5. <div class="header-content">
  6. <el-icon class="header-icon" :size="40"><FirstAidKit /></el-icon>
  7. <div>
  8. <h1 class="module-title">急救平台</h1>
  9. <p class="module-subtitle">Emergency Management Platform</p>
  10. </div>
  11. </div>
  12. <el-button @click="$router.push('/index')">
  13. <el-icon><HomeFilled /></el-icon>
  14. 返回门户
  15. </el-button>
  16. </div>
  17. <!-- 核心指标 -->
  18. <div class="stats-grid">
  19. <div v-for="(s, idx) in stats" :key="idx" class="stat-card" :class="s.color">
  20. <div class="stat-icon">
  21. <el-icon :size="32"><component :is="s.icon" /></el-icon>
  22. </div>
  23. <div class="stat-content">
  24. <div class="stat-value">{{ s.value }}</div>
  25. <div class="stat-label">{{ s.label }}</div>
  26. <div class="stat-extra">{{ s.extra }}</div>
  27. </div>
  28. </div>
  29. </div>
  30. <!-- 功能导航 -->
  31. <div class="nav-section">
  32. <h2 class="section-title">功能导航 ({{ navItems.length }} 个功能)</h2>
  33. <div class="nav-grid">
  34. <div
  35. v-for="item in navItems"
  36. :key="item.path"
  37. class="nav-card"
  38. @click="navigateTo(item.path)"
  39. >
  40. <div class="nav-icon" :style="{ background: item.bgColor, color: item.iconColor }">
  41. <el-icon :size="28"><component :is="item.icon" /></el-icon>
  42. </div>
  43. <div class="nav-body">
  44. <h3 class="nav-title">{{ item.title }}</h3>
  45. <p class="nav-desc">{{ item.desc }}</p>
  46. </div>
  47. </div>
  48. </div>
  49. </div>
  50. <!-- 常用快捷 -->
  51. <div class="quick-section">
  52. <h2 class="section-title">常用快捷</h2>
  53. <div class="quick-grid">
  54. <div
  55. v-for="item in navItems"
  56. :key="item.path"
  57. class="quick-item"
  58. @click="navigateTo(item.path)"
  59. >
  60. <el-icon :size="18" :style="{ color: item.iconColor }">
  61. <component :is="item.icon" />
  62. </el-icon>
  63. <span>{{ item.title }}</span>
  64. </div>
  65. </div>
  66. </div>
  67. </div>
  68. </template>
  69. <script setup lang="ts">
  70. import { useRouter } from 'vue-router';
  71. import {
  72. HomeFilled,
  73. Monitor,
  74. DataAnalysis,
  75. SetUp,
  76. Connection,
  77. Search,
  78. FirstAidKit
  79. } from '@element-plus/icons-vue';
  80. const router = useRouter();
  81. const stats = [
  82. { label: '在线救护车', value: '86', extra: '全市 118 辆', icon: Monitor, color: 'primary' },
  83. { label: '今日急救任务', value: '186', extra: '较昨日 +8.1%', icon: FirstAidKit, color: 'success' },
  84. { label: '平均出车响应', value: '03:21', extra: '目标 ≤ 04:00', icon: SetUp, color: 'warning' },
  85. { label: '待处置告警', value: '3', extra: '需及时关注', icon: Monitor, color: 'danger' },
  86. ];
  87. const navItems = [
  88. {
  89. title: '急救概览',
  90. path: '/emergency/overview',
  91. icon: Monitor,
  92. desc: '核心运行指标、地图工作台、实时任务',
  93. bgColor: 'linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%)',
  94. iconColor: '#409eff'
  95. },
  96. {
  97. title: '核心数据汇聚',
  98. path: '/emergency/data-hub',
  99. icon: DataAnalysis,
  100. desc: '数据接收链路、县区上传状态、实时监测',
  101. bgColor: 'linear-gradient(135deg, #f0f9eb 0%, #e1f3d8 100%)',
  102. iconColor: '#67c23a'
  103. },
  104. {
  105. title: '资源管理',
  106. path: '/emergency/resources',
  107. icon: SetUp,
  108. desc: '资源运行态势、车辆台账、设备配备',
  109. bgColor: 'linear-gradient(135deg, #fdf6ec 0%, #faecd8 100%)',
  110. iconColor: '#e6a23c'
  111. },
  112. {
  113. title: '网络布局',
  114. path: '/emergency/network',
  115. icon: Connection,
  116. desc: '三级网络示意图与完成度',
  117. bgColor: 'linear-gradient(135deg, #f0e6ff 0%, #e4d5f7 100%)',
  118. iconColor: '#9b59b6'
  119. },
  120. {
  121. title: '记录查询',
  122. path: '/emergency/records',
  123. icon: Search,
  124. desc: '急救任务记录检索与详情',
  125. bgColor: 'linear-gradient(135deg, #e8f8f5 0%, #d5f5e3 100%)',
  126. iconColor: '#1abc9c'
  127. },
  128. ];
  129. const navigateTo = (path: string) => {
  130. router.push(path);
  131. };
  132. </script>
  133. <style scoped lang="scss">
  134. .emergency-home-page {
  135. padding: 24px;
  136. background: #f5f7fa;
  137. min-height: 100vh;
  138. }
  139. .module-header {
  140. background: white;
  141. border-radius: 8px;
  142. padding: 24px;
  143. margin-bottom: 20px;
  144. display: flex;
  145. justify-content: space-between;
  146. align-items: center;
  147. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
  148. .header-content {
  149. display: flex;
  150. align-items: center;
  151. gap: 16px;
  152. .header-icon {
  153. color: #409eff;
  154. }
  155. .module-title {
  156. font-size: 28px;
  157. font-weight: 600;
  158. margin: 0 0 4px;
  159. color: #2c3e50;
  160. }
  161. .module-subtitle {
  162. font-size: 14px;
  163. color: #95a5a6;
  164. margin: 0;
  165. }
  166. }
  167. }
  168. .stats-grid {
  169. display: grid;
  170. grid-template-columns: repeat(4, 1fr);
  171. gap: 16px;
  172. margin-bottom: 20px;
  173. }
  174. .stat-card {
  175. background: white;
  176. border-radius: 8px;
  177. padding: 20px;
  178. display: flex;
  179. align-items: center;
  180. gap: 16px;
  181. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
  182. border-left: 4px solid;
  183. &.primary {
  184. border-left-color: #409eff;
  185. .stat-icon { background: #ecf5ff; color: #409eff; }
  186. }
  187. &.success {
  188. border-left-color: #67c23a;
  189. .stat-icon { background: #f0f9eb; color: #67c23a; }
  190. }
  191. &.warning {
  192. border-left-color: #e6a23c;
  193. .stat-icon { background: #fdf6ec; color: #e6a23c; }
  194. }
  195. &.danger {
  196. border-left-color: #f56c6c;
  197. .stat-icon { background: #fef0f0; color: #f56c6c; }
  198. }
  199. .stat-icon {
  200. width: 56px;
  201. height: 56px;
  202. border-radius: 12px;
  203. display: flex;
  204. align-items: center;
  205. justify-content: center;
  206. flex-shrink: 0;
  207. }
  208. .stat-content {
  209. flex: 1;
  210. min-width: 0;
  211. }
  212. .stat-value {
  213. font-size: 24px;
  214. font-weight: 700;
  215. color: #2c3e50;
  216. margin-bottom: 2px;
  217. }
  218. .stat-label {
  219. font-size: 13px;
  220. color: #909399;
  221. margin-bottom: 4px;
  222. }
  223. .stat-extra {
  224. font-size: 11px;
  225. color: #67c23a;
  226. }
  227. }
  228. .nav-section {
  229. background: white;
  230. border-radius: 8px;
  231. padding: 24px;
  232. margin-bottom: 20px;
  233. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
  234. .section-title {
  235. font-size: 18px;
  236. font-weight: 600;
  237. margin: 0 0 20px;
  238. color: #2c3e50;
  239. padding-left: 10px;
  240. border-left: 4px solid #409eff;
  241. }
  242. }
  243. .nav-grid {
  244. display: grid;
  245. grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  246. gap: 14px;
  247. }
  248. .nav-card {
  249. border: 1px solid #e4e7ed;
  250. border-radius: 8px;
  251. padding: 16px;
  252. cursor: pointer;
  253. transition: all 0.3s ease;
  254. display: flex;
  255. align-items: center;
  256. gap: 14px;
  257. &:hover {
  258. border-color: #409eff;
  259. box-shadow: 0 4px 14px rgba(64, 158, 255, 0.18);
  260. transform: translateY(-2px);
  261. }
  262. .nav-icon {
  263. width: 50px;
  264. height: 50px;
  265. border-radius: 10px;
  266. display: flex;
  267. align-items: center;
  268. justify-content: center;
  269. flex-shrink: 0;
  270. transition: all 0.3s;
  271. }
  272. .nav-body {
  273. flex: 1;
  274. min-width: 0;
  275. }
  276. .nav-title {
  277. font-size: 15px;
  278. font-weight: 600;
  279. margin: 0 0 4px;
  280. color: #2c3e50;
  281. overflow: hidden;
  282. text-overflow: ellipsis;
  283. white-space: nowrap;
  284. }
  285. .nav-desc {
  286. font-size: 12px;
  287. color: #909399;
  288. margin: 0;
  289. line-height: 1.5;
  290. overflow: hidden;
  291. text-overflow: ellipsis;
  292. white-space: nowrap;
  293. }
  294. }
  295. .quick-section {
  296. background: white;
  297. border-radius: 8px;
  298. padding: 24px;
  299. margin-bottom: 20px;
  300. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
  301. .section-title {
  302. font-size: 18px;
  303. font-weight: 600;
  304. margin: 0 0 20px;
  305. color: #2c3e50;
  306. padding-left: 10px;
  307. border-left: 4px solid #409eff;
  308. }
  309. }
  310. .quick-grid {
  311. display: grid;
  312. grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  313. gap: 12px;
  314. }
  315. .quick-item {
  316. display: flex;
  317. align-items: center;
  318. gap: 10px;
  319. padding: 14px 16px;
  320. border: 1px solid #e4e7ed;
  321. border-radius: 8px;
  322. cursor: pointer;
  323. transition: all 0.3s ease;
  324. background: #fafbfc;
  325. span {
  326. font-size: 14px;
  327. color: #2c3e50;
  328. font-weight: 500;
  329. }
  330. &:hover {
  331. border-color: #409eff;
  332. background: #ecf5ff;
  333. transform: translateY(-2px);
  334. box-shadow: 0 4px 12px rgba(64, 158, 255, 0.15);
  335. span {
  336. color: #409eff;
  337. }
  338. }
  339. }
  340. </style>