index.vue 4.41 KB
<script setup lang="ts">
import { ElMessage } from 'element-plus'
import { DemoApi, type DemoStatusVO } from '@/api/demo'
import { useUserStore } from '@/store'
import { formatDateTime } from '@/utils'

/**
 * 首页
 *
 * 这里承担「端到端联调自检」的职责:调用一次 /admin-api/demo/status,
 * 把后端应用名、数据库时间、Redis 连通性显示出来,用来证明
 * 「登录 → Bearer token → /admin-api → MySQL/Redis」这条链路是通的。
 */
defineOptions({ name: 'Dashboard' })

const userStore = useUserStore()
const loading = ref(false)
const status = ref<DemoStatusVO | null>(null)
const errorMsg = ref('')

async function loadStatus() {
  loading.value = true
  errorMsg.value = ''
  try {
    status.value = await DemoApi.getStatus()
  } catch (e: any) {
    errorMsg.value = e?.message || '自检接口调用失败'
  } finally {
    loading.value = false
  }
}

onMounted(loadStatus)

const nickname = computed(() => userStore.userInfo?.nickname || userStore.userInfo?.username || '-')
</script>

<template>
  <div class="app-container">
    <el-card shadow="never" class="mb-3">
      <div class="welcome">
        <el-avatar :size="42">{{ nickname.charAt(0) }}</el-avatar>
        <div class="welcome-text">
          <div class="welcome-title">你好,{{ nickname }}</div>
          <div class="welcome-sub">
            当前角色:{{ userStore.roles.join('、') || '无' }} ·
            已授权权限点:{{ userStore.permissions.length }} 个
          </div>
        </div>
      </div>
    </el-card>

    <el-row :gutter="12">
      <el-col :xs="24" :md="12">
        <el-card shadow="never">
          <template #header>
            <div class="card-header">
              <span>后端联调自检</span>
              <el-button link type="primary" :loading="loading" @click="loadStatus">刷新</el-button>
            </div>
          </template>

          <el-alert v-if="errorMsg" :title="errorMsg" type="error" :closable="false" class="mb-3" />

          <el-descriptions v-else :column="1" border size="small">
            <el-descriptions-item label="应用名称">
              {{ status?.applicationName || '-' }}
            </el-descriptions-item>
            <el-descriptions-item label="登录用户 ID">
              {{ status?.loginUserId ?? '-' }}
            </el-descriptions-item>
            <el-descriptions-item label="数据库时间">
              {{ status?.dbTime ? formatDateTime(status.dbTime) : '-' }}
            </el-descriptions-item>
            <el-descriptions-item label="服务端时间">
              {{ status?.serverTime ? formatDateTime(status.serverTime) : '-' }}
            </el-descriptions-item>
            <el-descriptions-item label="Redis 连通">
              <el-tag :type="status?.redisPing ? 'success' : 'danger'" size="small">
                {{ status?.redisPing ? '正常' : '异常' }}
              </el-tag>
            </el-descriptions-item>
          </el-descriptions>
        </el-card>
      </el-col>

      <el-col :xs="24" :md="12">
        <el-card shadow="never">
          <template #header>工程进度</template>
          <el-timeline>
            <el-timeline-item timestamp="P0 · 已完成" type="success" placement="top">
              后端骨架:单 Jar + 模块化单体 + 统一契约(已跑通)<br />
              前端骨架:登录 / 动态菜单路由 / 请求层
            </el-timeline-item>
            <el-timeline-item timestamp="P1 · 已完成" type="success" placement="top">
              系统管理域(用户/角色/菜单/组织/字典/日志)真实接口接入
            </el-timeline-item>
            <el-timeline-item timestamp="P2 · 下一步" type="primary" placement="top">
              停车/订单/支付/计费四模块原子合并,六库合一
            </el-timeline-item>
            <el-timeline-item timestamp="P3+" placement="top">
              充电模块 → 前端逐页迁移 → 政务平台并入 → 大屏重写
            </el-timeline-item>
          </el-timeline>
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>

<style scoped lang="scss">
.welcome {
  display: flex;
  align-items: center;
  gap: 14px;
}

.welcome-title {
  font-size: 16px;
  font-weight: 600;
}

.welcome-sub {
  margin-top: 4px;
  font-size: 12px;
  color: $text-color-secondary;
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
</style>