2025-09-01 18:18:44 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div class="app-container">
|
|
|
|
|
|
<a-layout style="min-height: 100%;">
|
2025-09-02 00:11:55 +08:00
|
|
|
|
<!-- 顶部导航栏:使用渐变淡蓝色背景 -->
|
2025-09-01 18:18:44 +08:00
|
|
|
|
<a-layout-header class="header">
|
2025-09-02 00:11:55 +08:00
|
|
|
|
<!-- 左侧Logo和系统名称 - 增加了图标 -->
|
2025-09-01 18:18:44 +08:00
|
|
|
|
<div class="logo">
|
2025-09-02 00:11:55 +08:00
|
|
|
|
<img src="/my.png" class="logo-img" />
|
|
|
|
|
|
<span class="system-name">cApi </span>
|
2025-09-01 18:18:44 +08:00
|
|
|
|
</div>
|
2025-09-02 00:11:55 +08:00
|
|
|
|
<!-- 主导航菜单:调整按钮大小和间距 -->
|
2025-09-01 18:18:44 +08:00
|
|
|
|
<a-menu
|
|
|
|
|
|
theme="light"
|
|
|
|
|
|
mode="horizontal"
|
|
|
|
|
|
:selectedKeys="selectedKey"
|
2025-09-02 00:11:55 +08:00
|
|
|
|
class="main-menu"
|
2025-09-01 18:18:44 +08:00
|
|
|
|
@click="handleMenuClick"
|
|
|
|
|
|
>
|
2025-09-02 00:11:55 +08:00
|
|
|
|
<a-menu-item key="app" class="menu-button">
|
|
|
|
|
|
<ApiOutlined class="menu-icon" />
|
|
|
|
|
|
<span>应用中心</span>
|
|
|
|
|
|
</a-menu-item>
|
|
|
|
|
|
<a-menu-item key="data" class="menu-button">
|
|
|
|
|
|
<DatabaseOutlined class="menu-icon" />
|
|
|
|
|
|
<span>数据中心</span>
|
|
|
|
|
|
</a-menu-item>
|
|
|
|
|
|
<a-menu-item key="integration" class="menu-button">
|
|
|
|
|
|
<LinkOutlined class="menu-icon" />
|
|
|
|
|
|
<span>集成中心</span>
|
|
|
|
|
|
</a-menu-item>
|
|
|
|
|
|
<a-menu-item key="system" class="menu-button">
|
|
|
|
|
|
<SettingOutlined class="menu-icon" />
|
|
|
|
|
|
<span>系统管理</span>
|
|
|
|
|
|
</a-menu-item>
|
2025-09-01 18:18:44 +08:00
|
|
|
|
</a-menu>
|
|
|
|
|
|
|
2025-09-02 00:11:55 +08:00
|
|
|
|
<!-- 右侧功能区:搜索框、图标和用户 -->
|
|
|
|
|
|
<div class="header-actions">
|
|
|
|
|
|
<!-- 搜索框 -->
|
|
|
|
|
|
<div class="search-box">
|
|
|
|
|
|
<SearchOutlined class="search-icon" />
|
|
|
|
|
|
<input type="text" placeholder="搜索" class="search-input" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 功能图标区 -->
|
|
|
|
|
|
<div class="action-icons">
|
|
|
|
|
|
<a-tooltip title="收藏">
|
|
|
|
|
|
<StarOutlined class="action-icon" />
|
|
|
|
|
|
</a-tooltip>
|
|
|
|
|
|
<a-tooltip title="通知">
|
|
|
|
|
|
<BellOutlined class="action-icon" />
|
|
|
|
|
|
</a-tooltip>
|
|
|
|
|
|
<a-tooltip title="帮助">
|
|
|
|
|
|
<QuestionCircleOutlined class="action-icon" />
|
|
|
|
|
|
</a-tooltip>
|
|
|
|
|
|
<a-tooltip title="设置">
|
|
|
|
|
|
<SettingOutlined class="action-icon" />
|
|
|
|
|
|
</a-tooltip>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 用户头像 -->
|
2025-09-01 18:18:44 +08:00
|
|
|
|
<a-dropdown
|
|
|
|
|
|
placement="bottomRight"
|
|
|
|
|
|
:auto-adjust-overflow="true"
|
|
|
|
|
|
@visible-change="handleDropdownVisible"
|
|
|
|
|
|
>
|
2025-09-02 00:11:55 +08:00
|
|
|
|
<div class="user-avatar">
|
|
|
|
|
|
<img src="https://picsum.photos/id/1005/200/200" alt="用户头像" class="avatar-img" />
|
|
|
|
|
|
</div>
|
2025-09-01 18:18:44 +08:00
|
|
|
|
<template #overlay>
|
2025-09-02 00:11:55 +08:00
|
|
|
|
<a-menu class="user-menu" @click="handleUserMenuClick">
|
|
|
|
|
|
<a-menu-item key="profile">个人资料</a-menu-item>
|
|
|
|
|
|
<a-menu-item key="settings">账户设置</a-menu-item>
|
|
|
|
|
|
<a-menu-divider />
|
2025-09-01 18:18:44 +08:00
|
|
|
|
<a-menu-item key="logout" class="logout-menu-item">
|
|
|
|
|
|
<LogoutOutlined class="mr-2" /> 退出登录
|
|
|
|
|
|
</a-menu-item>
|
|
|
|
|
|
</a-menu>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</a-dropdown>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</a-layout-header>
|
|
|
|
|
|
|
2025-09-02 00:11:55 +08:00
|
|
|
|
<!-- 标签栏:保持原有功能 -->
|
2025-09-01 18:18:44 +08:00
|
|
|
|
<div class="tab-bar">
|
|
|
|
|
|
<a-tag
|
|
|
|
|
|
:class="['console-tab', activeTabKey === 'console' ? 'console-tab--active' : '']"
|
|
|
|
|
|
@click="switchToConsole"
|
|
|
|
|
|
>
|
2025-09-02 00:11:55 +08:00
|
|
|
|
<HomeOutlined class="console-tab-icon" />
|
2025-09-01 18:18:44 +08:00
|
|
|
|
<span>控制台</span>
|
|
|
|
|
|
</a-tag>
|
|
|
|
|
|
|
|
|
|
|
|
<a-button
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
class="tab-nav-btn"
|
|
|
|
|
|
@click="switchTab('prev')"
|
|
|
|
|
|
:disabled="currentTabIndex === 0 || otherTabs.length === 0"
|
|
|
|
|
|
ghost
|
|
|
|
|
|
>
|
|
|
|
|
|
<
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
|
|
|
|
|
|
<a-tabs
|
|
|
|
|
|
v-model:activeKey="activeTabKey"
|
|
|
|
|
|
@change="handleTabChange"
|
|
|
|
|
|
class="google-tabs"
|
|
|
|
|
|
:animated="false"
|
|
|
|
|
|
hide-add
|
|
|
|
|
|
>
|
|
|
|
|
|
<a-tab-pane
|
|
|
|
|
|
v-for="tab in otherTabs"
|
|
|
|
|
|
:key="tab.key"
|
|
|
|
|
|
:tab="renderTabTitle(tab)"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</a-tabs>
|
|
|
|
|
|
|
|
|
|
|
|
<a-button
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
class="tab-nav-btn"
|
|
|
|
|
|
@click="switchTab('next')"
|
|
|
|
|
|
:disabled="currentTabIndex === otherTabs.length - 1 || otherTabs.length === 0"
|
|
|
|
|
|
ghost
|
|
|
|
|
|
>
|
|
|
|
|
|
>
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
|
|
|
|
|
|
<a-button
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
class="close-all-btn"
|
|
|
|
|
|
@click="closeAllTabs"
|
|
|
|
|
|
:disabled="otherTabs.length === 0"
|
|
|
|
|
|
ghost
|
|
|
|
|
|
>
|
|
|
|
|
|
<CloseOutlined class="close-icon" /> 关闭所有
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-09-02 00:11:55 +08:00
|
|
|
|
<!-- 内容区域:保持原有功能 -->
|
2025-09-01 18:18:44 +08:00
|
|
|
|
<a-layout-content class="content">
|
|
|
|
|
|
<div class="home-content">
|
|
|
|
|
|
<component
|
|
|
|
|
|
:is="currentMainComponent"
|
|
|
|
|
|
:key="activeTabKey"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</a-layout-content>
|
|
|
|
|
|
</a-layout>
|
|
|
|
|
|
|
2025-09-02 00:11:55 +08:00
|
|
|
|
<!-- 模块菜单弹窗:保持原有功能 -->
|
2025-09-01 18:18:44 +08:00
|
|
|
|
<a-modal
|
|
|
|
|
|
v-model:open="moduleModalVisible"
|
|
|
|
|
|
:title="currentModuleName"
|
|
|
|
|
|
:width="`80%`"
|
|
|
|
|
|
:centered="true"
|
|
|
|
|
|
:mask-closable="false"
|
|
|
|
|
|
@cancel="moduleModalVisible = false"
|
|
|
|
|
|
wrap-class-name="module-modal-wrapper"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="module-menu-container">
|
|
|
|
|
|
<a-row :gutter="[{ xs: 16, sm: 24 }, { xs: 16, sm: 24 }]">
|
|
|
|
|
|
<a-col
|
|
|
|
|
|
v-for="menu in currentModuleMenus"
|
|
|
|
|
|
:key="menu.key"
|
|
|
|
|
|
:xs="12"
|
|
|
|
|
|
:sm="8"
|
|
|
|
|
|
:md="6"
|
|
|
|
|
|
:lg="4"
|
|
|
|
|
|
:xl="3"
|
|
|
|
|
|
>
|
|
|
|
|
|
<a-card
|
|
|
|
|
|
class="menu-card"
|
|
|
|
|
|
@click="handleMenuCardClick(menu)"
|
|
|
|
|
|
hoverable
|
|
|
|
|
|
bordered
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="menu-card-inner">
|
|
|
|
|
|
<component :is="menu.icon" class="menu-icon" />
|
|
|
|
|
|
<div class="menu-title">{{ menu.title }}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</a-card>
|
|
|
|
|
|
</a-col>
|
|
|
|
|
|
</a-row>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</a-modal>
|
|
|
|
|
|
|
2025-09-02 00:11:55 +08:00
|
|
|
|
<!-- 退出确认对话框:保持原有功能 -->
|
2025-09-01 18:18:44 +08:00
|
|
|
|
<a-modal
|
|
|
|
|
|
v-model:open="logoutVisible"
|
|
|
|
|
|
:centered="true"
|
|
|
|
|
|
:closable="false"
|
|
|
|
|
|
:mask-closable="false"
|
|
|
|
|
|
:footer="null"
|
|
|
|
|
|
:width="420"
|
|
|
|
|
|
wrap-class-name="logout-modal-wrapper"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="logout-body">
|
|
|
|
|
|
<p class="logout-title">
|
|
|
|
|
|
<ExclamationCircleOutlined style="color:#faad14; margin-right:8px;" />
|
|
|
|
|
|
温馨提示
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p class="logout-desc">是否确认退出系统?</p>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="logout-actions">
|
|
|
|
|
|
<a-button size="large" @click="logoutVisible = false">取消</a-button>
|
|
|
|
|
|
<a-button
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
style="margin-left: 16px"
|
|
|
|
|
|
@click="doLogout"
|
|
|
|
|
|
>
|
|
|
|
|
|
确定
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</a-modal>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
import { ref, computed, h } from 'vue';
|
2025-09-02 00:11:55 +08:00
|
|
|
|
import { Layout, Menu, Button, Tabs, Card, Tag, Dropdown, Modal, Row, Col, Tooltip } from 'ant-design-vue';
|
2025-09-01 18:18:44 +08:00
|
|
|
|
import {
|
|
|
|
|
|
ApiOutlined,
|
|
|
|
|
|
UserOutlined,
|
|
|
|
|
|
CloseOutlined,
|
2025-09-02 00:11:55 +08:00
|
|
|
|
LinkOutlined,
|
2025-09-01 18:18:44 +08:00
|
|
|
|
LogoutOutlined,
|
|
|
|
|
|
ExclamationCircleOutlined,
|
|
|
|
|
|
BarChartOutlined,
|
|
|
|
|
|
DownloadOutlined,
|
|
|
|
|
|
SettingOutlined,
|
|
|
|
|
|
FormOutlined,
|
|
|
|
|
|
HistoryOutlined,
|
2025-09-02 00:11:55 +08:00
|
|
|
|
UserAddOutlined,
|
|
|
|
|
|
HomeOutlined,
|
|
|
|
|
|
DatabaseOutlined, // 用于系统名称前的图标
|
|
|
|
|
|
SearchOutlined,
|
|
|
|
|
|
StarOutlined,
|
|
|
|
|
|
BellOutlined,
|
|
|
|
|
|
QuestionCircleOutlined
|
2025-09-01 18:18:44 +08:00
|
|
|
|
} from '@ant-design/icons-vue';
|
|
|
|
|
|
|
|
|
|
|
|
// 导入Main组件(控制台要展示的内容)
|
2025-09-02 00:11:55 +08:00
|
|
|
|
import Main from './main.vue';
|
2025-09-01 18:18:44 +08:00
|
|
|
|
|
2025-09-02 00:11:55 +08:00
|
|
|
|
// 模拟业务组件
|
2025-09-01 18:18:44 +08:00
|
|
|
|
const MockComponent = (props) => {
|
|
|
|
|
|
return h('div', { style: { padding: '20px' } }, [
|
|
|
|
|
|
h('h3', `这是${props.title}页面`),
|
|
|
|
|
|
h('p', '此处将展示该功能模块的具体内容')
|
|
|
|
|
|
]);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 模块与菜单映射配置
|
|
|
|
|
|
const moduleMenusConfig = {
|
2025-09-02 00:11:55 +08:00
|
|
|
|
app: {
|
|
|
|
|
|
name: '应用中心',
|
2025-09-01 18:18:44 +08:00
|
|
|
|
menus: [
|
|
|
|
|
|
{
|
2025-09-02 00:11:55 +08:00
|
|
|
|
key: 'app-list',
|
|
|
|
|
|
title: '应用列表',
|
2025-09-01 18:18:44 +08:00
|
|
|
|
icon: ApiOutlined,
|
2025-09-02 00:11:55 +08:00
|
|
|
|
component: () => h(MockComponent, { title: '应用列表' }),
|
2025-09-01 18:18:44 +08:00
|
|
|
|
closable: true
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
2025-09-02 00:11:55 +08:00
|
|
|
|
key: 'app-create',
|
|
|
|
|
|
title: '创建应用',
|
2025-09-01 18:18:44 +08:00
|
|
|
|
icon: FormOutlined,
|
2025-09-02 00:11:55 +08:00
|
|
|
|
component: () => h(MockComponent, { title: '创建应用' }),
|
2025-09-01 18:18:44 +08:00
|
|
|
|
closable: true
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
data: {
|
2025-09-02 00:11:55 +08:00
|
|
|
|
name: '数据中心',
|
2025-09-01 18:18:44 +08:00
|
|
|
|
menus: [
|
|
|
|
|
|
{
|
|
|
|
|
|
key: 'data-analytics',
|
|
|
|
|
|
title: '数据分析',
|
|
|
|
|
|
icon: BarChartOutlined,
|
|
|
|
|
|
component: () => h(MockComponent, { title: '数据分析' }),
|
|
|
|
|
|
closable: true
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
key: 'data-export',
|
|
|
|
|
|
title: '数据导出',
|
|
|
|
|
|
icon: DownloadOutlined,
|
|
|
|
|
|
component: () => h(MockComponent, { title: '数据导出' }),
|
|
|
|
|
|
closable: true
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
2025-09-02 00:11:55 +08:00
|
|
|
|
integration: {
|
|
|
|
|
|
name: '集成中心',
|
|
|
|
|
|
menus: [
|
|
|
|
|
|
{
|
|
|
|
|
|
key: 'api-list',
|
|
|
|
|
|
title: 'API列表',
|
|
|
|
|
|
icon: ApiOutlined,
|
|
|
|
|
|
component: () => h(MockComponent, { title: 'API列表' }),
|
|
|
|
|
|
closable: true
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
key: 'integration-history',
|
|
|
|
|
|
title: '集成记录',
|
|
|
|
|
|
icon: HistoryOutlined,
|
|
|
|
|
|
component: () => h(MockComponent, { title: '集成记录' }),
|
|
|
|
|
|
closable: true
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
2025-09-01 18:18:44 +08:00
|
|
|
|
system: {
|
|
|
|
|
|
name: '系统管理',
|
|
|
|
|
|
menus: [
|
|
|
|
|
|
{
|
|
|
|
|
|
key: 'system-settings',
|
|
|
|
|
|
title: '系统设置',
|
|
|
|
|
|
icon: SettingOutlined,
|
|
|
|
|
|
component: () => h(MockComponent, { title: '系统设置' }),
|
|
|
|
|
|
closable: true
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
key: 'user-manage',
|
|
|
|
|
|
title: '用户管理',
|
|
|
|
|
|
icon: UserOutlined,
|
|
|
|
|
|
component: () => h(MockComponent, { title: '用户管理' }),
|
|
|
|
|
|
closable: true
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 状态管理
|
2025-09-02 00:11:55 +08:00
|
|
|
|
const selectedKey = ref(['console']);
|
2025-09-01 18:18:44 +08:00
|
|
|
|
const moduleModalVisible = ref(false);
|
2025-09-02 00:11:55 +08:00
|
|
|
|
const currentModuleKey = ref('console');
|
2025-09-01 18:18:44 +08:00
|
|
|
|
const activeTabKey = ref('console');
|
|
|
|
|
|
|
2025-09-02 00:11:55 +08:00
|
|
|
|
// 标签页数据
|
2025-09-01 18:18:44 +08:00
|
|
|
|
const allTabs = ref([
|
|
|
|
|
|
{
|
|
|
|
|
|
key: 'console',
|
|
|
|
|
|
title: '控制台',
|
2025-09-02 00:11:55 +08:00
|
|
|
|
component: Main,
|
|
|
|
|
|
closable: false
|
2025-09-01 18:18:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
// 计算属性
|
|
|
|
|
|
const otherTabs = computed(() =>
|
|
|
|
|
|
allTabs.value.filter(tab => tab.key !== 'console')
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const currentTabIndex = computed(() =>
|
|
|
|
|
|
otherTabs.value.findIndex(tab => tab.key === activeTabKey.value)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const currentModuleName = computed(() =>
|
|
|
|
|
|
moduleMenusConfig[currentModuleKey.value]?.name || '功能菜单'
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const currentModuleMenus = computed(() =>
|
|
|
|
|
|
moduleMenusConfig[currentModuleKey.value]?.menus || []
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const currentMainComponent = computed(() => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const targetTab = allTabs.value.find(tab => tab.key === activeTabKey.value);
|
|
|
|
|
|
return targetTab ? targetTab.component : null;
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('组件加载失败:', error);
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 事件处理
|
|
|
|
|
|
const renderTabTitle = (tab) => {
|
|
|
|
|
|
return h('div', { class: 'tab-title-container' }, [
|
|
|
|
|
|
h('span', { class: 'tab-title-text' }, tab.title),
|
|
|
|
|
|
tab.closable && h(
|
|
|
|
|
|
'span',
|
|
|
|
|
|
{
|
|
|
|
|
|
class: 'tab-close-btn',
|
|
|
|
|
|
onClick: (e) => {
|
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
deleteTab(tab.key);
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
h(CloseOutlined, { size: 12 })
|
|
|
|
|
|
)
|
|
|
|
|
|
]);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const switchToConsole = () => {
|
|
|
|
|
|
activeTabKey.value = 'console';
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const switchTab = (direction) => {
|
|
|
|
|
|
if (direction === 'prev' && currentTabIndex.value > 0) {
|
|
|
|
|
|
activeTabKey.value = otherTabs.value[currentTabIndex.value - 1].key;
|
|
|
|
|
|
} else if (
|
|
|
|
|
|
direction === 'next' &&
|
|
|
|
|
|
currentTabIndex.value < otherTabs.value.length - 1
|
|
|
|
|
|
) {
|
|
|
|
|
|
activeTabKey.value = otherTabs.value[currentTabIndex.value + 1].key;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const deleteTab = (key) => {
|
|
|
|
|
|
if (key === 'console') return;
|
|
|
|
|
|
const tabIndex = allTabs.value.findIndex(tab => tab.key === key);
|
|
|
|
|
|
if (tabIndex === -1) return;
|
|
|
|
|
|
allTabs.value = allTabs.value.filter(tab => tab.key !== key);
|
|
|
|
|
|
if (key === activeTabKey.value) {
|
|
|
|
|
|
const targetTab = allTabs.value[tabIndex - 1] || allTabs.value.find(tab => tab.key === 'console');
|
|
|
|
|
|
activeTabKey.value = targetTab.key;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const closeAllTabs = () => {
|
|
|
|
|
|
allTabs.value = allTabs.value.filter(tab => tab.key === 'console');
|
|
|
|
|
|
activeTabKey.value = 'console';
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleTabChange = (key) => {
|
|
|
|
|
|
activeTabKey.value = key;
|
2025-09-02 00:11:55 +08:00
|
|
|
|
// 根据标签页映射到对应的模块
|
2025-09-01 18:18:44 +08:00
|
|
|
|
const tabToModuleMap = {
|
2025-09-02 00:11:55 +08:00
|
|
|
|
'dashboard': 'console',
|
|
|
|
|
|
'tasks': 'console',
|
|
|
|
|
|
'app-list': 'app',
|
|
|
|
|
|
'app-create': 'app',
|
2025-09-01 18:18:44 +08:00
|
|
|
|
'data-analytics': 'data',
|
|
|
|
|
|
'data-export': 'data',
|
2025-09-02 00:11:55 +08:00
|
|
|
|
'api-list': 'integration',
|
|
|
|
|
|
'integration-history': 'integration',
|
2025-09-01 18:18:44 +08:00
|
|
|
|
'system-settings': 'system',
|
2025-09-02 00:11:55 +08:00
|
|
|
|
'user-manage': 'system'
|
2025-09-01 18:18:44 +08:00
|
|
|
|
};
|
2025-09-02 00:11:55 +08:00
|
|
|
|
selectedKey.value = [tabToModuleMap[key] || 'console'];
|
2025-09-01 18:18:44 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleMenuClick = ({ key }) => {
|
|
|
|
|
|
currentModuleKey.value = key;
|
|
|
|
|
|
moduleModalVisible.value = true;
|
|
|
|
|
|
selectedKey.value = [key];
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleMenuCardClick = (menuItem) => {
|
|
|
|
|
|
moduleModalVisible.value = false;
|
|
|
|
|
|
const isTabExists = allTabs.value.some(tab => tab.key === menuItem.key);
|
|
|
|
|
|
if (!isTabExists) {
|
|
|
|
|
|
allTabs.value.push({
|
|
|
|
|
|
key: menuItem.key,
|
|
|
|
|
|
title: menuItem.title,
|
|
|
|
|
|
component: menuItem.component,
|
|
|
|
|
|
closable: menuItem.closable
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
activeTabKey.value = menuItem.key;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleDropdownVisible = (visible) => {
|
|
|
|
|
|
console.log('下拉菜单状态:', visible ? '显示' : '隐藏');
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-09-02 00:11:55 +08:00
|
|
|
|
const handleUserMenuClick = ({ key }) => {
|
|
|
|
|
|
if (key === 'logout') {
|
|
|
|
|
|
handleLogout();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
console.log('用户菜单点击:', key);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2025-09-01 18:18:44 +08:00
|
|
|
|
|
2025-09-02 00:11:55 +08:00
|
|
|
|
const logoutVisible = ref(false);
|
2025-09-01 18:18:44 +08:00
|
|
|
|
const handleLogout = () => {
|
|
|
|
|
|
logoutVisible.value = true;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const doLogout = () => {
|
|
|
|
|
|
localStorage.removeItem('token');
|
|
|
|
|
|
localStorage.removeItem('userInfo');
|
|
|
|
|
|
logoutVisible.value = false;
|
|
|
|
|
|
alert('退出登录成功,即将跳转到登录页');
|
2025-09-02 00:11:55 +08:00
|
|
|
|
// 实际项目中应该使用路由跳转
|
|
|
|
|
|
// router.push('/login');
|
2025-09-01 18:18:44 +08:00
|
|
|
|
};
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
2025-09-02 00:11:55 +08:00
|
|
|
|
/* 基础样式 */
|
2025-09-01 18:18:44 +08:00
|
|
|
|
* {
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
}
|
|
|
|
|
|
html,
|
|
|
|
|
|
body,
|
|
|
|
|
|
.app-container {
|
|
|
|
|
|
height: 100vh;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
.app-container {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-02 00:11:55 +08:00
|
|
|
|
/* 顶部导航:使用渐变淡蓝色背景 */
|
2025-09-01 18:18:44 +08:00
|
|
|
|
.header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
padding: 0 20px;
|
|
|
|
|
|
height: 64px;
|
|
|
|
|
|
width: 100%;
|
2025-09-02 00:11:55 +08:00
|
|
|
|
background: linear-gradient(90deg, #e6f7ff 0%, #f0f9ff 100%);
|
|
|
|
|
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
2025-09-01 18:18:44 +08:00
|
|
|
|
}
|
2025-09-02 00:11:55 +08:00
|
|
|
|
|
|
|
|
|
|
/* Logo和系统名称 - 添加了图标样式 */
|
2025-09-01 18:18:44 +08:00
|
|
|
|
.logo {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
2025-09-02 00:11:55 +08:00
|
|
|
|
padding-right: 20px;
|
|
|
|
|
|
border-right: 1px solid rgba(24, 144, 255, 0.1);
|
|
|
|
|
|
gap: 10px; /* 图标与文字间距 */
|
|
|
|
|
|
}
|
|
|
|
|
|
.logo-icon {
|
|
|
|
|
|
color: #1890ff;
|
|
|
|
|
|
font-size: 22px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.logo-img {
|
|
|
|
|
|
width: 65px; /* 与文字高度匹配,可根据图片比例调整 */
|
|
|
|
|
|
height: 65px;
|
|
|
|
|
|
object-fit: contain; /* 关键:保持图片比例,避免拉伸变形 */
|
|
|
|
|
|
vertical-align: middle; /* 与文字垂直居中对齐 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.system-name {
|
2025-09-01 18:18:44 +08:00
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #1890ff;
|
|
|
|
|
|
}
|
2025-09-02 00:11:55 +08:00
|
|
|
|
|
|
|
|
|
|
/* 主导航菜单:优化按钮样式 */
|
|
|
|
|
|
.main-menu {
|
2025-09-01 18:18:44 +08:00
|
|
|
|
flex: 1;
|
2025-09-02 00:11:55 +08:00
|
|
|
|
margin: 0 25px;
|
|
|
|
|
|
justify-content: flex-start;
|
|
|
|
|
|
}
|
|
|
|
|
|
:deep(.ant-menu-horizontal) {
|
|
|
|
|
|
background: transparent !important;
|
|
|
|
|
|
border-bottom: none !important;
|
2025-09-01 18:18:44 +08:00
|
|
|
|
}
|
2025-09-02 00:11:55 +08:00
|
|
|
|
/* 调整按钮大小和间距 */
|
|
|
|
|
|
.menu-button {
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
margin: 110 120px !important;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
margin-top: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
:deep(.ant-menu-item) {
|
|
|
|
|
|
color: #096dd9 !important; /* 加深文字颜色,增强对比 */
|
|
|
|
|
|
font-size: 13px; /* 缩小字体 */
|
|
|
|
|
|
padding: 0 12px !important; /* 减小内边距 */
|
|
|
|
|
|
height: 36px !important; /* 减小按钮高度 */
|
|
|
|
|
|
line-height: 36px !important;
|
|
|
|
|
|
background-color: rgba(255, 255, 255, 0.8) !important; /* 调整背景透明度 */
|
|
|
|
|
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
|
|
|
|
}
|
|
|
|
|
|
:deep(.ant-menu-item-selected) {
|
|
|
|
|
|
background-color: #fff !important;
|
|
|
|
|
|
color: #096dd9 !important;
|
|
|
|
|
|
box-shadow: 0 2px 6px rgba(24, 144, 255, 0.2);
|
|
|
|
|
|
}
|
|
|
|
|
|
:deep(.ant-menu-item:hover:not(.ant-menu-item-selected)) {
|
|
|
|
|
|
background-color: #fff !important;
|
|
|
|
|
|
color: #096dd9 !important;
|
|
|
|
|
|
transform: translateY(-1px);
|
|
|
|
|
|
box-shadow: 0 2px 5px rgba(24, 144, 255, 0.15);
|
|
|
|
|
|
}
|
|
|
|
|
|
.menu-icon {
|
|
|
|
|
|
margin-right: 6px; /* 减小图标与文字间距 */
|
|
|
|
|
|
font-size: 14px; /* 缩小图标 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 右侧功能区 */
|
|
|
|
|
|
.header-actions {
|
2025-09-01 18:18:44 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
2025-09-02 00:11:55 +08:00
|
|
|
|
gap: 16px;
|
2025-09-01 18:18:44 +08:00
|
|
|
|
}
|
2025-09-02 00:11:55 +08:00
|
|
|
|
|
|
|
|
|
|
/* 搜索框 */
|
|
|
|
|
|
.search-box {
|
2025-09-01 18:18:44 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
2025-09-02 00:11:55 +08:00
|
|
|
|
background: rgba(255, 255, 255, 0.8);
|
2025-09-01 18:18:44 +08:00
|
|
|
|
border-radius: 4px;
|
2025-09-02 00:11:55 +08:00
|
|
|
|
padding: 0 12px;
|
|
|
|
|
|
height: 36px;
|
|
|
|
|
|
width: 240px;
|
|
|
|
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
2025-09-01 18:18:44 +08:00
|
|
|
|
}
|
2025-09-02 00:11:55 +08:00
|
|
|
|
.search-icon {
|
|
|
|
|
|
color: #8c8c8c;
|
|
|
|
|
|
margin-right: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.search-input {
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
outline: none;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.search-input::placeholder {
|
|
|
|
|
|
color: #b3b3b3;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 功能图标区 */
|
|
|
|
|
|
.action-icons {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 16px;
|
|
|
|
|
|
padding-right: 16px;
|
|
|
|
|
|
border-right: 1px solid rgba(24, 144, 255, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
.action-icon {
|
2025-09-01 18:18:44 +08:00
|
|
|
|
color: #1890ff;
|
2025-09-02 00:11:55 +08:00
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: all 0.2s;
|
|
|
|
|
|
}
|
|
|
|
|
|
.action-icon:hover {
|
|
|
|
|
|
color: #096dd9;
|
|
|
|
|
|
transform: scale(1.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 用户头像 */
|
|
|
|
|
|
.user-avatar {
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
.avatar-img {
|
|
|
|
|
|
width: 36px;
|
|
|
|
|
|
height: 36px;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
object-fit: cover;
|
|
|
|
|
|
border: 2px solid transparent;
|
|
|
|
|
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
transition: all 0.2s;
|
2025-09-01 18:18:44 +08:00
|
|
|
|
}
|
2025-09-02 00:11:55 +08:00
|
|
|
|
.user-avatar:hover .avatar-img {
|
|
|
|
|
|
border-color: #1890ff;
|
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
|
box-shadow: 0 4px 8px rgba(24, 144, 255, 0.2);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 用户菜单 */
|
|
|
|
|
|
.user-menu {
|
|
|
|
|
|
width: 160px;
|
2025-09-01 18:18:44 +08:00
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
|
|
|
|
}
|
|
|
|
|
|
.logout-menu-item {
|
2025-09-02 00:11:55 +08:00
|
|
|
|
color: #f5222d !important;
|
2025-09-01 18:18:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-02 00:11:55 +08:00
|
|
|
|
/* 标签栏:保持原有样式 */
|
2025-09-01 18:18:44 +08:00
|
|
|
|
.tab-bar {
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
border-bottom: 1px solid #e0e0e0;
|
|
|
|
|
|
padding: 0 20px;
|
|
|
|
|
|
height: 44px;
|
|
|
|
|
|
margin-top: 2px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
.console-tab {
|
|
|
|
|
|
height: 32px;
|
|
|
|
|
|
padding: 0 16px;
|
|
|
|
|
|
border-radius: 6px 6px 0 0;
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
|
}
|
2025-09-02 00:11:55 +08:00
|
|
|
|
.console-tab-icon {
|
|
|
|
|
|
margin-right: 6px;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
2025-09-01 18:18:44 +08:00
|
|
|
|
.console-tab--active {
|
|
|
|
|
|
background: #e8f4ff !important;
|
|
|
|
|
|
color: #1890ff;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
box-shadow: 0 1px 2px rgba(24, 144, 255, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
.console-tab:hover:not(.console-tab--active) {
|
|
|
|
|
|
background: #f5f9ff;
|
|
|
|
|
|
color: #1890ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 标签导航按钮 */
|
|
|
|
|
|
.tab-nav-btn {
|
|
|
|
|
|
width: 28px;
|
|
|
|
|
|
height: 28px;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.tab-nav-btn:hover {
|
|
|
|
|
|
background: #f5f9ff;
|
|
|
|
|
|
color: #1890ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
.tab-nav-btn:disabled {
|
|
|
|
|
|
color: #ccc !important;
|
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
|
background: transparent !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 标签页样式 */
|
|
|
|
|
|
.google-tabs {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
.ant-tabs-nav {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
margin: 0 !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
.ant-tabs-nav-list {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
.ant-tabs-tab {
|
|
|
|
|
|
height: 36px;
|
|
|
|
|
|
padding: 0 16px;
|
|
|
|
|
|
margin: 0 2px;
|
|
|
|
|
|
border-radius: 6px 6px 0 0;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
}
|
|
|
|
|
|
.ant-tabs-tab:hover:not(.ant-tabs-tab-active) {
|
|
|
|
|
|
background: #f5f9ff;
|
|
|
|
|
|
color: #1890ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
.ant-tabs-tab.ant-tabs-tab-active {
|
|
|
|
|
|
background: #e8f4ff !important;
|
|
|
|
|
|
color: #1890ff !important;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
box-shadow: 0 1px 2px rgba(24, 144, 255, 0.1);
|
|
|
|
|
|
border-bottom: 2px solid #1890ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
.ant-tabs-ink-bar {
|
|
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 标签标题容器 */
|
|
|
|
|
|
.tab-title-container {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 6px;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
padding: 0 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.tab-title-text {
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
.tab-close-btn {
|
|
|
|
|
|
width: 16px;
|
|
|
|
|
|
height: 16px;
|
|
|
|
|
|
display: none;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: all 0.2s;
|
|
|
|
|
|
}
|
|
|
|
|
|
.tab-title-container:hover .tab-close-btn {
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
}
|
|
|
|
|
|
.ant-tabs-tab-active .tab-close-btn {
|
|
|
|
|
|
color: #1890ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
.tab-close-btn:hover {
|
|
|
|
|
|
background: #d1eaff;
|
|
|
|
|
|
color: #1890ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 关闭所有按钮 */
|
|
|
|
|
|
.close-all-btn {
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
margin-left: 2px;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
padding: 0 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.close-all-btn:hover {
|
|
|
|
|
|
color: #1890ff;
|
|
|
|
|
|
background: #f5f9ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
.close-all-btn:disabled {
|
|
|
|
|
|
color: #ccc !important;
|
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
|
background: transparent !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
.close-icon {
|
|
|
|
|
|
margin-right: 4px;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-02 00:11:55 +08:00
|
|
|
|
/* 内容区域:保持原有样式 */
|
2025-09-01 18:18:44 +08:00
|
|
|
|
.content {
|
|
|
|
|
|
background: #f8f9fa;
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
flex-grow: 1;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
.home-content {
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
padding: 24px;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
overflow: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-02 00:11:55 +08:00
|
|
|
|
/* 模块菜单弹窗:保持原有样式 */
|
2025-09-01 18:18:44 +08:00
|
|
|
|
.module-modal-wrapper .ant-modal-content {
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.module-menu-container {
|
|
|
|
|
|
padding: 24px 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
.menu-card {
|
|
|
|
|
|
height: 160px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
border-color: #e8e8e8;
|
|
|
|
|
|
}
|
|
|
|
|
|
.menu-card:hover {
|
|
|
|
|
|
border-color: #1890ff;
|
|
|
|
|
|
box-shadow: 0 4px 16px rgba(24, 144, 255, 0.15);
|
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
|
}
|
|
|
|
|
|
.menu-card-inner {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
.menu-icon {
|
|
|
|
|
|
font-size: 32px;
|
|
|
|
|
|
color: #1890ff;
|
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
|
transition: color 0.3s;
|
|
|
|
|
|
}
|
|
|
|
|
|
.menu-card:hover .menu-icon {
|
|
|
|
|
|
color: #096dd9;
|
|
|
|
|
|
}
|
|
|
|
|
|
.menu-title {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-02 00:11:55 +08:00
|
|
|
|
/* 退出对话框:保持原有样式 */
|
2025-09-01 18:18:44 +08:00
|
|
|
|
.logout-modal-wrapper .ant-modal {
|
|
|
|
|
|
width: 480px !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
.logout-body {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
padding: 8px 0 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.logout-title {
|
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
margin-bottom: 12px;
|
|
|
|
|
|
text-align: left;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
}
|
|
|
|
|
|
.logout-desc {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
color: #555;
|
|
|
|
|
|
margin-bottom: 32px;
|
|
|
|
|
|
text-align: left;
|
|
|
|
|
|
}
|
|
|
|
|
|
.logout-actions {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
margin-top: 24px;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|