| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- <template>
- <div class="p-4 md:p-8">
- <!-- 统计卡片区域 -->
- <a-row :gutter="[16, 16]" class="mb-4 md:mb-8">
- <!-- 工厂总数卡片 -->
- <a-col :xs="24" :sm="12" :lg="6">
- <a-card class="stat-card bg-gradient-to-br from-blue-500 to-blue-600 text-white rounded-xl shadow-lg hover:shadow-xl hover:scale-105 transition-all duration-300 !border-0">
- <div class="flex items-center justify-between">
- <div>
- <div class="text-sm opacity-80 mb-2">工厂总数</div>
- <div class="text-4xl font-bold">{{ dashboardData.factory_count }}</div>
- <div class="text-sm mt-2 opacity-70">家</div>
- </div>
- <ShopOutlined class="text-5xl opacity-80" />
- </div>
- </a-card>
- </a-col>
- <!-- 启用工厂卡片 -->
- <a-col :xs="24" :sm="12" :lg="6">
- <a-card class="stat-card bg-gradient-to-br from-green-500 to-green-600 text-white rounded-xl shadow-lg hover:shadow-xl hover:scale-105 transition-all duration-300 !border-0">
- <div class="flex items-center justify-between">
- <div>
- <div class="text-sm opacity-80 mb-2">启用工厂</div>
- <div class="text-4xl font-bold">{{ dashboardData.enabled_factory_count }}</div>
- <div class="text-sm mt-2 opacity-70">家</div>
- </div>
- <CheckCircleOutlined class="text-5xl opacity-80" />
- </div>
- </a-card>
- </a-col>
- <!-- 系统用户卡片 -->
- <a-col :xs="24" :sm="12" :lg="6">
- <a-card class="stat-card bg-gradient-to-br from-purple-500 to-purple-600 text-white rounded-xl shadow-lg hover:shadow-xl hover:scale-105 transition-all duration-300 !border-0">
- <div class="flex items-center justify-between">
- <div>
- <div class="text-sm opacity-80 mb-2">系统用户</div>
- <div class="text-4xl font-bold">{{ dashboardData.user_count }}</div>
- <div class="text-sm mt-2 opacity-70">人</div>
- </div>
- <UserOutlined class="text-5xl opacity-80" />
- </div>
- </a-card>
- </a-col>
- <!-- 审计日志卡片 -->
- <a-col :xs="24" :sm="12" :lg="6">
- <a-card class="stat-card bg-gradient-to-br from-orange-500 to-orange-600 text-white rounded-xl shadow-lg hover:shadow-xl hover:scale-105 transition-all duration-300 !border-0">
- <div class="flex items-center justify-between">
- <div>
- <div class="text-sm opacity-80 mb-2">审计日志</div>
- <div class="text-4xl font-bold">{{ dashboardData.log_count }}</div>
- <div class="text-sm mt-2 opacity-70">条</div>
- </div>
- <FileTextOutlined class="text-5xl opacity-80" />
- </div>
- </a-card>
- </a-col>
- </a-row>
- <!-- 快捷操作卡片 -->
- <a-card class="rounded-xl shadow-md !border-0" title="快捷操作">
- <template #extra>
- <span class="text-gray-400 text-sm">常用功能快速访问</span>
- </template>
- <a-space size="large">
- <a-button
- type="primary"
- size="large"
- @click="router.push('/factories')"
- class="shadow-md hover:shadow-lg transition-shadow"
- >
- <ShopOutlined class="mr-2" />
- 管理工厂
- </a-button>
- <a-button
- size="large"
- @click="router.push('/users')"
- class="shadow-sm hover:shadow-md transition-shadow"
- >
- <UserOutlined class="mr-2" />
- 系统用户
- </a-button>
- </a-space>
- </a-card>
- </div>
- </template>
- <script setup lang="ts">
- import { ref, onMounted } from 'vue';
- import { useRouter } from 'vue-router';
- import { message } from 'ant-design-vue';
- import { ShopOutlined, CheckCircleOutlined, UserOutlined, FileTextOutlined } from '@ant-design/icons-vue';
- import { SystemFactoryApi, SystemUserApi, AuditLogApi, createApiClient } from '@smartcut/api-client';
- import { STORAGE_KEYS } from '@smartcut/shared-utils';
- import { getApiBaseUrl } from '@/apiConfig';
- const router = useRouter();
- const dashboardData = ref({
- factory_count: 0,
- enabled_factory_count: 0,
- user_count: 0,
- log_count: 0
- });
- const apiClient = createApiClient({
- baseURL: getApiBaseUrl(),
- tokenKey: STORAGE_KEYS.PLATFORM_TOKEN
- });
- const factoryApi = new SystemFactoryApi(apiClient);
- const userApi = new SystemUserApi(apiClient);
- const auditLogApi = new AuditLogApi(apiClient);
- onMounted(async () => {
- // 并行获取三组数据,任一失败不影响其他卡片
- const [factoryRes, userRes, logRes] = await Promise.allSettled([
- factoryApi.listFactories(),
- userApi.getUsers({ page: 1, page_size: 1 }),
- auditLogApi.getAuditLogs({ page: 1, page_size: 1 })
- ]);
- if (factoryRes.status === 'fulfilled') {
- dashboardData.value.factory_count = factoryRes.value.total;
- dashboardData.value.enabled_factory_count = factoryRes.value.list.filter(f => f.status === 1).length;
- }
- if (userRes.status === 'fulfilled') {
- dashboardData.value.user_count = userRes.value.total;
- }
- if (logRes.status === 'fulfilled') {
- dashboardData.value.log_count = logRes.value.total;
- }
- // 三组全部失败时才提示错误
- if (factoryRes.status === 'rejected' && userRes.status === 'rejected' && logRes.status === 'rejected') {
- message.error('加载看板数据失败');
- }
- });
- </script>
|