feat(桌面): 基础+欢迎界面
parent
57444011dc
commit
a4f2096c5d
|
@ -1,5 +1,7 @@
|
||||||
import { defineConfig } from 'umi';
|
import { defineConfig } from 'umi';
|
||||||
import { Platform, Arch } from '@umijs/plugin-electron';
|
import { Platform, Arch } from '@umijs/plugin-electron';
|
||||||
|
const path = require('path');
|
||||||
|
const rootdir = path.join(__dirname, ".");
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
npmClient: 'yarn',
|
npmClient: 'yarn',
|
||||||
|
@ -13,29 +15,39 @@ export default defineConfig({
|
||||||
mfsu: false,
|
mfsu: false,
|
||||||
hash: true,
|
hash: true,
|
||||||
styles: ['src/global.less'],
|
styles: ['src/global.less'],
|
||||||
|
alias: {
|
||||||
|
"@": path.resolve(rootdir, "src"),
|
||||||
|
"@assets": path.resolve(rootdir, "src/assets"),
|
||||||
|
"@components": path.resolve(rootdir, "src/components"),
|
||||||
|
"@utils": path.resolve(rootdir, "src/utils"),
|
||||||
|
},
|
||||||
// 路由配置
|
// 路由配置
|
||||||
routes: [
|
routes: [
|
||||||
{
|
// {
|
||||||
path: '/login',
|
// path: '/',
|
||||||
component: '@/pages/login',
|
// component: '@/pages/welcome',
|
||||||
},
|
// },
|
||||||
|
// {
|
||||||
|
// path: '/login',
|
||||||
|
// component: '@/pages/login',
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
component: '@/pages/components/Layout/index',
|
component: '@/pages/components/Layout/index',
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: '/images',
|
path: '/welcome',
|
||||||
component: '@/pages/images',
|
component: '@/pages/welcome',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/profile',
|
path: '/login',
|
||||||
component: '@/pages/profile',
|
component: '@/pages/login',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
redirect: '/welcome',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/',
|
|
||||||
redirect: '@/pages/login',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
{
|
{
|
||||||
"name": "@umijs/electron-template",
|
"name": "vdi-manager",
|
||||||
"version": "1.0.2",
|
"version": "1.0.5",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@umijs/electron-template",
|
"name": "vdi-manager",
|
||||||
"version": "1.0.2",
|
"version": "1.0.5",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^6.0.0",
|
"@ant-design/icons": "^6.0.0",
|
||||||
"antd": "^5.26.6",
|
"antd": "^5.26.6",
|
||||||
|
"axios": "^1.11.0",
|
||||||
"umi": "^4.0.42"
|
"umi": "^4.0.42"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -7352,7 +7353,6 @@
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
|
"resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/at-least-node": {
|
"node_modules/at-least-node": {
|
||||||
|
@ -7426,6 +7426,17 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/axios": {
|
||||||
|
"version": "1.11.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.11.0.tgz",
|
||||||
|
"integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.15.6",
|
||||||
|
"form-data": "^4.0.4",
|
||||||
|
"proxy-from-env": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/babel-jest": {
|
"node_modules/babel-jest": {
|
||||||
"version": "29.7.0",
|
"version": "29.7.0",
|
||||||
"resolved": "https://registry.npmmirror.com/babel-jest/-/babel-jest-29.7.0.tgz",
|
"resolved": "https://registry.npmmirror.com/babel-jest/-/babel-jest-29.7.0.tgz",
|
||||||
|
@ -8528,7 +8539,6 @@
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
|
"resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"delayed-stream": "~1.0.0"
|
"delayed-stream": "~1.0.0"
|
||||||
|
@ -9479,7 +9489,6 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
|
@ -11359,6 +11368,26 @@
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/follow-redirects": {
|
||||||
|
"version": "1.15.11",
|
||||||
|
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
||||||
|
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"debug": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/for-each": {
|
"node_modules/for-each": {
|
||||||
"version": "0.3.5",
|
"version": "0.3.5",
|
||||||
"resolved": "https://registry.npmmirror.com/for-each/-/for-each-0.3.5.tgz",
|
"resolved": "https://registry.npmmirror.com/for-each/-/for-each-0.3.5.tgz",
|
||||||
|
@ -11481,7 +11510,6 @@
|
||||||
"version": "4.0.4",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.4.tgz",
|
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.4.tgz",
|
||||||
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"asynckit": "^0.4.0",
|
"asynckit": "^0.4.0",
|
||||||
|
@ -16648,6 +16676,12 @@
|
||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/proxy-from-env": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/prr": {
|
"node_modules/prr": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/prr/-/prr-1.0.1.tgz",
|
"resolved": "https://registry.npmmirror.com/prr/-/prr-1.0.1.tgz",
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^6.0.0",
|
"@ant-design/icons": "^6.0.0",
|
||||||
"antd": "^5.26.6",
|
"antd": "^5.26.6",
|
||||||
|
"axios": "^1.11.0",
|
||||||
"umi": "^4.0.42"
|
"umi": "^4.0.42"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,15 @@
|
||||||
|
import { BrowserWindowConstructorOptions } from "electron";
|
||||||
|
export default{
|
||||||
|
browserWindow:{
|
||||||
|
kiosk: true,
|
||||||
|
frame: false,
|
||||||
|
titleBarStyle: 'hidden',
|
||||||
|
autoHideMenuBar: true,
|
||||||
|
// 禁止调整窗口大小
|
||||||
|
resizable: false,
|
||||||
|
// 禁止最大化和最小化按钮
|
||||||
|
maximizable: false,
|
||||||
|
minimizable: false,
|
||||||
|
closable: false,
|
||||||
|
} as BrowserWindowConstructorOptions,
|
||||||
|
}
|
|
@ -1 +1 @@
|
||||||
// getBrowserWindowRuntime().webContents.openDevTools();
|
getBrowserWindowRuntime().webContents.openDevTools();
|
||||||
|
|
|
@ -1,5 +1,23 @@
|
||||||
import { ipcMain } from 'electron';
|
import { ipcMain,app } from 'electron';
|
||||||
|
|
||||||
|
const window = getBrowserWindowRuntime();
|
||||||
|
|
||||||
|
// 监听渲染进程发送的消息
|
||||||
ipcMain.handle('getPlatform', () => {
|
ipcMain.handle('getPlatform', () => {
|
||||||
return `hi, i'm from ${process.platform}`;
|
return `hi, i'm from ${process.platform}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 窗口控制:最小化,退出全屏
|
||||||
|
ipcMain.on('close-app', () => {
|
||||||
|
app.quit();
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on('minimize-app', () => {
|
||||||
|
window?.minimize();
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on('exit-kiosk', () => {
|
||||||
|
if (window) {
|
||||||
|
window.setFullScreen(false);
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,7 +1,31 @@
|
||||||
import { contextBridge, ipcRenderer } from 'electron';
|
import { contextBridge, ipcRenderer } from 'electron';
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('$api', {
|
// 页面调用的方法
|
||||||
|
contextBridge.exposeInMainWorld('electronAPI', {
|
||||||
getPlatform: async () => {
|
getPlatform: async () => {
|
||||||
return await ipcRenderer.invoke('getPlatform');
|
return await ipcRenderer.invoke('getPlatform');
|
||||||
},
|
},
|
||||||
|
closeApp: () => ipcRenderer.send('close-app'),
|
||||||
|
minimizeApp: () => ipcRenderer.send('minimize-app'),
|
||||||
|
exitKiosk: () => ipcRenderer.send('exit-kiosk'),
|
||||||
|
// 事件监听
|
||||||
|
onMainProcessMessage: (callback: (data: string) => void) => {
|
||||||
|
ipcRenderer.on('main-process-message', (_, data) => callback(data));
|
||||||
|
},
|
||||||
|
on(...args: Parameters<typeof ipcRenderer.on>) {
|
||||||
|
const [channel, listener] = args
|
||||||
|
return ipcRenderer.on(channel, (event, ...args) => listener(event, ...args))
|
||||||
|
},
|
||||||
|
off(...args: Parameters<typeof ipcRenderer.off>) {
|
||||||
|
const [channel, ...omit] = args
|
||||||
|
return ipcRenderer.off(channel, ...omit)
|
||||||
|
},
|
||||||
|
send(...args: Parameters<typeof ipcRenderer.send>) {
|
||||||
|
const [channel, ...omit] = args
|
||||||
|
return ipcRenderer.send(channel, ...omit)
|
||||||
|
},
|
||||||
|
invoke(...args: Parameters<typeof ipcRenderer.invoke>) {
|
||||||
|
const [channel, ...omit] = args
|
||||||
|
return ipcRenderer.invoke(channel, ...omit)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,64 +1,9 @@
|
||||||
.main-layout {
|
.main-layout {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.main-sider {
|
.main-content {
|
||||||
.logo {
|
min-height: 100vh;
|
||||||
height: 64px;
|
}
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
color: white;
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: bold;
|
|
||||||
border-bottom: 1px solid #303030;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-header {
|
|
||||||
background: #fff;
|
|
||||||
padding: 0 24px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
|
|
||||||
.trigger {
|
|
||||||
font-size: 18px;
|
|
||||||
color: #666;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #1890ff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-right {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 16px;
|
|
||||||
|
|
||||||
.welcome-text {
|
|
||||||
color: #666;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-avatar {
|
|
||||||
cursor: pointer;
|
|
||||||
background: #1890ff;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-content {
|
|
||||||
// margin: 24px;
|
|
||||||
// padding: 24px;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
min-height: calc(100vh - 112px);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,34 +1,33 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Layout, Menu, Button, Avatar, Dropdown, message } from 'antd';
|
import { Layout, message } from 'antd';
|
||||||
import {
|
|
||||||
AppstoreOutlined,
|
|
||||||
UserOutlined,
|
|
||||||
LogoutOutlined,
|
|
||||||
MenuFoldOutlined,
|
|
||||||
MenuUnfoldOutlined,
|
|
||||||
} from '@ant-design/icons';
|
|
||||||
import { history, useLocation, Outlet } from 'umi';
|
import { history, useLocation, Outlet } from 'umi';
|
||||||
import './index.less';
|
import './index.less';
|
||||||
|
|
||||||
const { Header, Sider, Content } = Layout;
|
const { Header, Sider, Content } = Layout;
|
||||||
|
|
||||||
const MainLayout: React.FC = () => {
|
const MainLayout: React.FC = () => {
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
|
||||||
const [username, setUsername] = useState('');
|
const [username, setUsername] = useState('');
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// // 检查登录状态
|
||||||
|
// const isLoggedIn = localStorage.getItem('isLoggedIn');
|
||||||
|
// const currentUsername = localStorage.getItem('username');
|
||||||
|
|
||||||
|
// if (!isLoggedIn) {
|
||||||
|
// message.error('请先登录!');
|
||||||
|
// history.push('/login');
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// setUsername(currentUsername || '');
|
||||||
|
// }, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 检查登录状态
|
// TODO: 第一次来:判断是否配置ip/DHCP、服务ip绑定终端 绑定:直接到版本更新页面 未绑定:到配置ip/DHCP页面
|
||||||
const isLoggedIn = localStorage.getItem('isLoggedIn');
|
setTimeout(() => {
|
||||||
const currentUsername = localStorage.getItem('username');
|
history.push('/login');
|
||||||
|
},9000)
|
||||||
if (!isLoggedIn) {
|
|
||||||
message.error('请先登录!');
|
|
||||||
history.push('/login');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setUsername(currentUsername || '');
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleMenuClick = (key: string) => {
|
const handleMenuClick = (key: string) => {
|
||||||
|
@ -43,73 +42,11 @@ const MainLayout: React.FC = () => {
|
||||||
history.push('/login');
|
history.push('/login');
|
||||||
};
|
};
|
||||||
|
|
||||||
const userMenu = (
|
|
||||||
<Menu>
|
|
||||||
<Menu.Item key="profile" icon={<UserOutlined />} onClick={() => history.push('/profile')}>
|
|
||||||
个人资料
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Divider />
|
|
||||||
<Menu.Item key="logout" icon={<LogoutOutlined />} onClick={handleLogout}>
|
|
||||||
退出登录
|
|
||||||
</Menu.Item>
|
|
||||||
</Menu>
|
|
||||||
);
|
|
||||||
|
|
||||||
// 根据当前路径确定选中的菜单项
|
|
||||||
const getSelectedKey = () => {
|
|
||||||
const path = location.pathname;
|
|
||||||
if (path === '/images') return 'images';
|
|
||||||
if (path === '/profile') return 'profile';
|
|
||||||
return 'images'; // 默认选中镜像列表
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout className="main-layout">
|
<Layout className="main-layout">
|
||||||
<Sider
|
<Content className="main-content">
|
||||||
trigger={null}
|
<Outlet />
|
||||||
collapsible
|
</Content>
|
||||||
collapsed={collapsed}
|
|
||||||
className="main-sider"
|
|
||||||
>
|
|
||||||
<div className="logo">
|
|
||||||
{!collapsed && <span>VDI 系统</span>}
|
|
||||||
</div>
|
|
||||||
<Menu
|
|
||||||
theme="dark"
|
|
||||||
mode="inline"
|
|
||||||
selectedKeys={[getSelectedKey()]}
|
|
||||||
onClick={({ key }) => handleMenuClick(key)}
|
|
||||||
>
|
|
||||||
<Menu.Item key="images" icon={<AppstoreOutlined />}>
|
|
||||||
镜像列表
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item key="profile" icon={<UserOutlined />}>
|
|
||||||
我的
|
|
||||||
</Menu.Item>
|
|
||||||
</Menu>
|
|
||||||
</Sider>
|
|
||||||
|
|
||||||
<Layout>
|
|
||||||
<Header className="main-header">
|
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
icon={collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
|
|
||||||
onClick={() => setCollapsed(!collapsed)}
|
|
||||||
className="trigger"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="header-right">
|
|
||||||
<span className="welcome-text">欢迎,{username}</span>
|
|
||||||
<Dropdown overlay={userMenu} placement="bottomRight">
|
|
||||||
<Avatar icon={<UserOutlined />} className="user-avatar" />
|
|
||||||
</Dropdown>
|
|
||||||
</div>
|
|
||||||
</Header>
|
|
||||||
|
|
||||||
<Content className="main-content">
|
|
||||||
<Outlet />
|
|
||||||
</Content>
|
|
||||||
</Layout>
|
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,6 +33,24 @@ const LoginPage: React.FC = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const closeApp = () => {
|
||||||
|
if (window.electronAPI) {
|
||||||
|
window.electronAPI.closeApp();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const minimizeApp = () => {
|
||||||
|
if (window.electronAPI) {
|
||||||
|
window.electronAPI.minimizeApp();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const exitKioskMode = () => {
|
||||||
|
if (window.electronAPI) {
|
||||||
|
window.electronAPI.exitKiosk();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="login-container">
|
<div className="login-container">
|
||||||
<div className="login-content">
|
<div className="login-content">
|
||||||
|
@ -74,7 +92,11 @@ const LoginPage: React.FC = () => {
|
||||||
</Button>
|
</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
|
<div>
|
||||||
|
<Button onClick={closeApp}>关闭应用</Button>
|
||||||
|
<Button onClick={minimizeApp}>最小化</Button>
|
||||||
|
<Button onClick={exitKioskMode}>退出全屏模式</Button>
|
||||||
|
</div>
|
||||||
<div className="login-tips">
|
<div className="login-tips">
|
||||||
<p>提示:用户名 admin,密码 123456</p>
|
<p>提示:用户名 admin,密码 123456</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
.welcomeCon{
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background-color: rgba(0, 9, 51, 1);
|
||||||
|
background-size: 100% 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
.showTextCon{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-self: center;
|
||||||
|
align-items: center;
|
||||||
|
.name{
|
||||||
|
height: 80px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 36px;
|
||||||
|
color: #e5e5e5;
|
||||||
|
display: flex;
|
||||||
|
.welcomeIcon{
|
||||||
|
height: 66px;
|
||||||
|
width: 70px;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
.textCon{
|
||||||
|
height: 120px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
.text{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
.nameText{
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.loadingCon{
|
||||||
|
width: 96px;
|
||||||
|
height: 12px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
.dot {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: rgba(255, 255, 255, 0.3);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
animation: loading 1.5s infinite ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot:nth-child(1) {
|
||||||
|
animation-delay: -0.32s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot:nth-child(2) {
|
||||||
|
animation-delay: -0.16s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes loading {
|
||||||
|
0%, 100% {
|
||||||
|
background-color: rgba(255, 255, 255, 0.3);
|
||||||
|
transform: scale(0.6);
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
background-color: rgba(255, 255, 255, 0.6);
|
||||||
|
transform: scale(0.8);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
background-color: rgba(255, 255, 255, 1);
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
background-color: rgba(255, 255, 255, 0.6);
|
||||||
|
transform: scale(0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
import React from 'react';
|
||||||
|
import styles from './index.less';
|
||||||
|
import WelcomeIcon from '../../assets/welcome-icon.jpg'
|
||||||
|
|
||||||
|
const Welcome = () => {
|
||||||
|
return (
|
||||||
|
<div className={styles.welcomeCon} >
|
||||||
|
<div className={styles.showTextCon}>
|
||||||
|
<div className={styles.name}>
|
||||||
|
<img src={WelcomeIcon} className={styles.welcomeIcon} />
|
||||||
|
<div className={styles.textCon}>
|
||||||
|
<div className={styles.text}>
|
||||||
|
<span>紫光汇智</span>
|
||||||
|
<span className={styles.nameText}>UNISSENSE</span>
|
||||||
|
</div>
|
||||||
|
<div className={styles.loadingCon}>
|
||||||
|
<div className={styles.dot}></div>
|
||||||
|
<div className={styles.dot}></div>
|
||||||
|
<div className={styles.dot}></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Welcome;
|
|
@ -0,0 +1,20 @@
|
||||||
|
import axios from '@/utils/axios';
|
||||||
|
|
||||||
|
export const BASE_URL = '/api/v1/test';
|
||||||
|
|
||||||
|
export const getPageConfig = async () => {
|
||||||
|
const res = await axios({
|
||||||
|
url: `${BASE_URL}/page-config/1`,
|
||||||
|
method: 'GET',
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getTruckList = async (params) => {
|
||||||
|
const res = await axios({
|
||||||
|
url: `${BASE_URL}/listCarInfo`,
|
||||||
|
method: 'POST',
|
||||||
|
data: params,
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
};
|
|
@ -0,0 +1,52 @@
|
||||||
|
import axios from 'axios';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
const HTTP_CODE_SUCCESS = '0000000000';
|
||||||
|
|
||||||
|
function getCookie(name: string): string {
|
||||||
|
let arr;
|
||||||
|
const reg = new RegExp(`(^| )${name}=([^;]*)(;|$)`);
|
||||||
|
if ((arr = document.cookie.match(reg))) return decodeURIComponent(arr[2]);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// headers
|
||||||
|
function getHeaders(headers = {}) {
|
||||||
|
// const userCode = getCookie('usercode') || 'admin';
|
||||||
|
// const userName = getCookie('username') || 'admin';
|
||||||
|
return {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
// Authorization: encodeURIComponent(`username:${userName}&usercode:${userCode}`),
|
||||||
|
// User: encodeURIComponent(`username:${userName}&usercode:${userCode}`),
|
||||||
|
...headers,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const instance = axios.create({
|
||||||
|
timeout: 30000,
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.interceptors.request.use(config => {
|
||||||
|
const _headers = getHeaders();
|
||||||
|
config.headers = { ..._headers, ...config.headers };
|
||||||
|
if (config.method === 'get' && config.params) {
|
||||||
|
config.params.t = +new Date;
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}, error => {
|
||||||
|
return Promise.reject(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.interceptors.response.use(res => {
|
||||||
|
if (res?.data?.error_code === HTTP_CODE_SUCCESS) {
|
||||||
|
res.data.hzApiStatu = true;
|
||||||
|
}
|
||||||
|
return res.data;
|
||||||
|
}, rej => {
|
||||||
|
if (!rej?.config?.$refusedDefaultDealError && rej?.response?.data?.message) {
|
||||||
|
message.error(rej.response.data.message);
|
||||||
|
}
|
||||||
|
return Promise.reject(rej.response);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default instance;
|
|
@ -2,6 +2,6 @@ import 'umi/typings';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
$api: any;
|
electronAPI: any;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue