Compare commits

..

No commits in common. "b584915bb71ba6156a3b0a423f33261c22a36c59" and "e2c223b22e6bb6c58152b302da6d224827651e96" have entirely different histories.

12 changed files with 104 additions and 481 deletions

View File

@ -24,18 +24,18 @@ export default defineConfig({
},
// 路由配置
routes: [
// {
// path: '/',
// component: '@/pages/welcome',
// },
// {
// path: '/login',
// component: '@/pages/login',
// },
{
path: '/',
component: '@/pages/components/Layout/index',
routes: [
{
path: '/imagesList',
component: '@/pages/imagesList',
},
{
path: '/login',
component: '@/pages/login',
},
{
path: '/grpc',
component: '@/pages/grpc/grpc',
@ -44,6 +44,10 @@ export default defineConfig({
path: '/welcome',
component: '@/pages/welcome',
},
{
path: '/login',
component: '@/pages/login',
},
{
path: '/configSteps',
component: '@/pages/configSteps',

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -1,28 +1 @@
getBrowserWindowRuntime().webContents.openDevTools();
// import { BrowserWindow } from 'electron';
// import path from 'path';
// // 修复:添加默认值处理
// const APP_ROOT = process.env.APP_ROOT || '.';
// const MAIN_DIST = path.join(APP_ROOT, 'dist-electron');
// getBrowserWindowRuntime().webContents.openDevTools();
// const createNewWindow = () => {
// const newWindow = new BrowserWindow({
// width: 200,
// height: 200,
// webPreferences: {
// nodeIntegration: true,
// contextIsolation: false
// }
// });
// // 加载页面内容
// newWindow.loadURL('file:/' + __dirname + '/index.html');
// return newWindow;
// };
// createNewWindow();

View File

@ -12,54 +12,16 @@ const window = getBrowserWindowRuntime();
let currentServerIp: string | undefined;
// 添加处理窗口调整
ipcMain.handle('adjust-window-for-normal', async (event) => {
try {
const window = BrowserWindow.fromWebContents(event.sender);
if (window) {
// 调整窗口大小和配置
window.setKiosk(false); // 退出全屏模式
window.setMinimumSize(1200, 800);
window.setSize(1200, 800);
window.setResizable(true);
window.setMaximizable(true);
window.setMinimizable(true);
// 保持无边框和隐藏标题栏的设置
window.setFullScreen(false);
}
return { success: true };
} catch (error) {
console.error('调整窗口失败:', error);
return { success: false, };
}
});
/**拖动窗口 */
ipcMain.handle('drag-window', (event) => {
const focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow) {
// 通知渲染进程开始拖拽
focusedWindow.webContents.send('start-drag');
}
});
// 监听渲染进程发送的消息
ipcMain.handle('getPlatform', () => {
return `hi, i'm from ${process.platform}`;
});
// 窗口控制:最小化,退出全屏,关闭,
// 获取窗口最大化状态
ipcMain.handle('get-window-maximized', (event) => {
const window = BrowserWindow.fromWebContents(event.sender);
return window?.isMaximized() || false;
});
// 窗口控制:最小化,退出全屏
ipcMain.on('close-app', () => {
app.quit();
});
// 最小化
ipcMain.on('minimize-app', () => {
const focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow) {
@ -68,39 +30,16 @@ ipcMain.on('minimize-app', () => {
// window?.minimize();
});
// 退出全屏
ipcMain.on('restore-window', () => {
ipcMain.on('exit-kiosk', () => {
const focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow) {
focusedWindow.unmaximize();
focusedWindow.setFullScreen(false);
}
// if (window) {
// window.setFullScreen(false);
// }
});
// 设置全屏
ipcMain.on('maximize-window', () => {
const focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow) {
focusedWindow.maximize();
}
})
// 监听窗口状态变化并通知渲染进程
ipcMain.on('register-window-state-listeners', (event) => {
const window = BrowserWindow.fromWebContents(event.sender);
if (window) {
window.on('maximize', () => {
event.sender.send('window-maximized');
});
window.on('unmaximize', () => {
event.sender.send('window-unmaximized');
});
}
});
ipcMain.handle('get-device-id',async()=>{
const deviceId = await getDeviceId();

View File

@ -7,14 +7,12 @@ contextBridge.exposeInMainWorld('electronAPI', {
},
closeApp: () => ipcRenderer.send('close-app'),
minimizeApp: () => ipcRenderer.send('minimize-app'),
restoreWindow: () => ipcRenderer.send('restore-window'),
maximizeWindow: () => ipcRenderer.send('maximize-window'),
getWindowMaximized: () => ipcRenderer.invoke('get-window-maximized'),
adjustWindowForNormal:() => ipcRenderer.invoke('adjust-window-for-normal'),
exitKiosk: () => ipcRenderer.send('exit-kiosk'),
// 版本更新相关API
downloadAndUpdate: (url: string) => ipcRenderer.invoke('download-and-update', url),
// 服务器IP获取
getCurrentServerIp: () => ipcRenderer.invoke('get-current-server-ip'),
// 事件监听
onMainProcessMessage: (callback: (data: string) => void) => {
ipcRenderer.on('main-process-message', (_, data) => callback(data));

View File

@ -1,108 +0,0 @@
// src/pages/components/TitleBar/index.less
.title-bar {
margin: 20px 0;
padding: 0 20px;
width: 100%;
height: 34px;
display: flex;
justify-content: space-between;
align-items: center;
-webkit-app-region: drag; // 使整个标题栏可拖动
user-select: none;
.title-bar-right {
display: flex;
align-items: center;
-webkit-app-region: no-drag; // 使按钮区域不可拖动
.window-control {
width: 18px;
height: 18px;
border: 1.5px solid rgba(34, 34, 34, 1);
margin-left: 10px;
cursor: pointer;
&.minimize {
// 最小化按钮样式(一条线)
position: relative;
&::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 10px;
height: 1.5px;
background-color: rgba(34, 34, 34, 1);
}
}
&.restore {
position: relative;
&::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 8px;
height: 8px;
border: 1px solid rgba(34, 34, 34, 1);
}
&::after {
content: '';
position: absolute;
top: 30%;
left: 30%;
width: 8px;
height: 8px;
border: 1px solid rgba(34, 34, 34, 1);
background: white;
}
}
&.maximize {
// 最大化按钮样式(正方形框)
position: relative;
&::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 10px;
height: 10px;
border: 1px solid rgba(34, 34, 34, 1);
}
}
&.close {
// 关闭按钮样式(×)
position: relative;
&::before,
&::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 12px;
height: 1.5px;
background-color: rgba(34, 34, 34, 1);
}
&::before {
transform: translate(-50%, -50%) rotate(45deg);
}
&::after {
transform: translate(-50%, -50%) rotate(-45deg);
}
}
}
}
}

View File

@ -1,71 +0,0 @@
// src/pages/components/TitleBar/index.tsx
import React,{ useState, useEffect } from 'react';
import './index.less';
import BarIcon from '@assets/barIcon.png'
const TitleBar = () => {
const [isMaximized, setIsMaximized] = useState(false);
// 监听窗口状态变化
useEffect(() => {
if (window.electronAPI) {
// 注册窗口状态变化监听器
window.electronAPI.send('register-window-state-listeners');
window.electronAPI.on('window-maximized', () => {
setIsMaximized(true);
});
window.electronAPI.on('window-unmaximized', () => {
setIsMaximized(false);
});
// 初始化时获取窗口状态
window.electronAPI.getWindowMaximized().then((maximized: boolean) => {
setIsMaximized(maximized);
});
}
}, []);
const closeApp = () => {
if (window.electronAPI) {
window.electronAPI.closeApp();
}
};
const minimizeApp = () => {
if (window.electronAPI) {
window.electronAPI.minimizeApp();
}
};
// 区分当前是最小化还是最大化
const toggleMaximize = () => {
if (window.electronAPI) {
if (isMaximized) {
window.electronAPI.restoreWindow();
} else {
window.electronAPI.maximizeWindow();
}
}
};
return (
<div className="title-bar" onMouseDown={(e) => {
// 只有点击在标题栏空白处才触发拖动
if (e.target === e.currentTarget) {
window.electronAPI.send('drag-window');
}
}}>
<div className="title-bar-left">
<img src={BarIcon} />
</div>
<div className="title-bar-right">
<div className="window-control minimize" onClick={minimizeApp}></div>
<div className={`window-control ${isMaximized ? 'restore' : 'maximize'}`} onClick={toggleMaximize}></div>
<div className="window-control close" onClick={closeApp}></div>
</div>
</div>
);
};
export default TitleBar;

View File

@ -74,18 +74,8 @@ const Index = () => {
</div>
);
const handleSubmit = async() => {
try {
// 调用主进程调整窗口
if (window.electronAPI) {
await window.electronAPI.adjustWindowForNormal();
}
// 跳转到登录页面
history.push('/login');
} catch (error) {
console.error('跳转登录页失败:', error);
message.error('跳转失败,请重试');
}
const handleSubmit = () => {
history.push('/login');
}
return (

View File

@ -1,11 +0,0 @@
import React from 'react';
const Index = () => {
return (
<div>
</div>
);
}
export default Index;

View File

@ -1,142 +1,34 @@
.login-container {
display: flex;
justify-content: space-between;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.login-content {
width: 100%;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
max-width: 400px;
padding: 20px;
}
.login-card {
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
border-radius: 12px;
width: 390px;
height: 520px;
padding: 0 30px;
padding-top: 79px;
box-sizing: border-box;
.ant-card-body {
padding: 0;
}
}
.ant-card-head {
text-align: center;
border-bottom: 1px solid #f0f0f0;
.welcome-text {
font-family: "Microsoft YaHei UI";
font-weight: 700;
font-style: normal;
font-size: 20px;
line-height: 100%;
letter-spacing: 0%;
color: rgba(36, 47, 72, 1);
margin-bottom: 40px;
text-align: center;
}
.input-group {
margin-bottom: 40px;
.ant-form-item {
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
.ant-card-head-title {
font-size: 24px;
font-weight: 600;
color: #333;
}
}
}
.custom-input {
width: 330px;
height: 39px;
border-radius: 8px;
background: rgba(255, 255, 255, 1);
border: 1px solid rgba(215, 217, 224, 1);
.ant-input-prefix {
margin-right: 0;
}
.input-icon {
width: 18px;
height: 18px;
margin-left: 10px;
margin-right: 14px;
}
&::placeholder {
font-family: "Microsoft YaHei UI";
font-weight: 400;
font-style: normal;
font-size: 16px;
line-height: 100%;
letter-spacing: 0%;
color: rgba(160, 163, 173, 1);
}
input {
font-family: "Microsoft YaHei UI";
font-weight: 400;
font-style: normal;
font-size: 16px;
line-height: 100%;
letter-spacing: 0%;
color: rgba(160, 163, 173, 1);
}
}
.login-button {
height: 39px;
border-radius: 8px;
background: rgba(1, 90, 255, 1);
border: none;
font-family: "Microsoft YaHei UI";
font-weight: 400;
font-style: normal;
font-size: 16px;
line-height: 100%;
letter-spacing: 0%;
color: rgba(255, 255, 255, 1);
width: 100%;
&:hover {
background: rgba(1, 90, 255, 0.9);
}
}
.checkbox-group {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
}
.custom-checkbox {
font-family: "Microsoft YaHei UI";
font-weight: 400;
font-style: normal;
font-size: 14px;
line-height: 100%;
letter-spacing: 0%;
color: rgba(88, 97, 116, 1);
.ant-checkbox-inner {
width: 16px;
height: 16px;
}
.ant-checkbox-checked .ant-checkbox-inner {
background-color: rgba(1, 90, 255, 1);
border-color: rgba(1, 90, 255, 1);
}
&:first-child {
margin-right: 10px;
.ant-card-body {
padding: 32px 24px;
}
}
@ -157,3 +49,30 @@
.ant-form-item {
margin-bottom: 24px;
}
.ant-input-affix-wrapper {
border-radius: 6px;
border: 1px solid #d9d9d9;
&:hover,
&:focus,
&.ant-input-affix-wrapper-focused {
border-color: #667eea;
box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.2);
}
}
.ant-btn-primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
border-radius: 6px;
height: 44px;
font-size: 16px;
font-weight: 500;
&:hover {
background: linear-gradient(135deg, #5a6fd8 0%, #6a4190 100%);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}
}

View File

@ -1,14 +1,12 @@
import React, { useState } from 'react';
import { Form, Input, Button, Card, message, Checkbox } from 'antd';
import { UserOutlined, LockOutlined, LinkOutlined } from '@ant-design/icons';
import { Form, Input, Button, Card, message } from 'antd';
import { UserOutlined, LockOutlined } from '@ant-design/icons';
import { history } from 'umi';
import TitleBar from '../components/TitleBar';
import './index.less';
interface LoginForm {
username: string;
password: string;
server: string;
}
const LoginPage: React.FC = () => {
@ -24,7 +22,7 @@ const LoginPage: React.FC = () => {
localStorage.setItem('isLoggedIn', 'true');
localStorage.setItem('username', values.username);
// 跳转到镜像列表页面
history.push('/imagesList');
history.push('/images');
} else {
message.error('用户名或密码错误!');
}
@ -35,60 +33,53 @@ const LoginPage: React.FC = () => {
}
};
const test = () => {
setTimeout(() => {
// history.push('/login');
history.push('/configSteps?tab=terminalGetImage');
},1000)
}
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 (
<div className="login-container">
<TitleBar />
<Button onClick={test}></Button>
<div className="login-content">
<Card className="login-card" bordered={false}>
<div className="welcome-text"> X Space</div>
<Card className="login-card" title="系统登录" bordered={false}>
<Form
name="login"
onFinish={onFinish}
autoComplete="off"
size="large"
>
<div className="input-group">
<Form.Item
name="username"
rules={[{ required: true, message: '请输入账户名!' }]}
>
<Input
prefix={<UserOutlined className="input-icon" />}
placeholder="请输入账户名"
className="custom-input"
/>
</Form.Item>
<Form.Item
name="username"
rules={[{ required: true, message: '请输入用户名!' }]}
>
<Input
prefix={<UserOutlined />}
placeholder="用户名"
/>
</Form.Item>
<Form.Item
name="password"
rules={[{ required: true, message: '请输入密码!' }]}
>
<Input.Password
prefix={<LockOutlined className="input-icon" />}
placeholder="请输入密码"
className="custom-input"
/>
</Form.Item>
<Form.Item
name="server"
rules={[{ required: true, message: '请输入服务器地址!' }]}
>
<Input
prefix={<LinkOutlined className="input-icon" />}
placeholder="请输入服务器地址"
className="custom-input"
/>
</Form.Item>
</div>
<Form.Item
name="password"
rules={[{ required: true, message: '请输入密码!' }]}
>
<Input.Password
prefix={<LockOutlined />}
placeholder="密码"
/>
</Form.Item>
<Form.Item>
<Button
@ -96,17 +87,16 @@ const LoginPage: React.FC = () => {
htmlType="submit"
loading={loading}
block
className="login-button"
>
</Button>
</Form.Item>
</Form>
<div className="checkbox-group">
<Checkbox className="custom-checkbox"></Checkbox>
<Checkbox className="custom-checkbox"></Checkbox>
</div>
<div>
<Button onClick={closeApp}></Button>
<Button onClick={minimizeApp}></Button>
<Button onClick={exitKioskMode}>退</Button>
</div>
<div className="login-tips">
<p> admin 123456</p>
</div>