Compare commits

...

No commits in common. 'main' and 'master_basic' have entirely different histories.

9
.gitignore vendored

@ -0,0 +1,9 @@
/node_modules
/.env.local
/.umirc.local.ts
/config/config.local.ts
/src/.umi
/src/.umi-production
/src/.umi-test
/dist
.swc

@ -0,0 +1,2 @@
registry=https://registry.npmmirror.com/

@ -0,0 +1,10 @@
import { defineConfig } from "umi";
import routes from './config/routes/index';
import proxy from './config/proxy';
export default defineConfig({
proxy,
hash: true,
routes,
npmClient: 'yarn',
});

@ -1,2 +0,0 @@
# xgd_system

@ -0,0 +1,11 @@
import GlobalConfig from '../src/utils/env/dev';
const proxy = {
'/xgd': {
target: GlobalConfig['PROXY_SERVER'],
changeOrigin: true,
withCredentials: true,
secure: false,
cookieDomainRewrite: 'localhost',
}
};
export default proxy;

@ -0,0 +1,151 @@
const routes = [
{ path: '/', redirect: '/index', }, // 本地跑时为了方便先使用这个
// { path: '/', redirect: '/404', }, // 后续上线时开放
// 桌面
{ path: '/index', name: '桌面', component: '@/pages/index', layout: false },
// ------------------------------流程------------------------------
{ path: '/installExe/:fileType', name: '01MMD049安装.exe', component: '@/pages/InstallExe', layout: false },
{ path: '/initialSystem/:fileType', name: '初装系统', component: '@/pages/InitialSystem', layout: false },
{ path: '/coreSystemEntrance', name: '核心管理系统', component: '@/pages/CoreSystemEntrance', layout: false },
// ------------------------------GLQ远程维护----------------------------------
// 建立远程链接
{ path: '/teamViewer/paramsSetting', name: '参数设置', component: '@/pages/GLQ/TeamViewer/ParamsSetting' },
// 交互维护命令
{ path: '/teamViewer/systemTime', name: '系统时间', component: '@/pages/GLQ/TeamViewer/SystemTime' },
{ path: '/teamViewer/currentIP', name: '当前IP', component: '@/pages/GLQ/TeamViewer/CurrentIP' },
{ path: '/teamViewer/pingCommand', name: 'PING命令', component: '@/pages/GLQ/TeamViewer/PingCommand' },
{ path: '/teamViewer/telnetCommand', name: 'TELNET命令', component: '@/pages/GLQ/TeamViewer/TelnetCommand' },
{ path: '/teamViewer/otherCommand', name: '其他命令', component: '@/pages/GLQ/TeamViewer/OtherCommand' },
// ---------------------------------------------------------------------------
// ------------------------------网络MMJ管理----------------------------------
{ path: '/webMMJ/mmjInitInstall', name: 'MMJ初装', component: '@/pages/GLQ/WebMMJ/MmjInitInstall' },
{ path: '/webMMJ/statusQuery', name: '状态查询', component: '@/pages/GLQ/WebMMJ/StatusQuery' },
{ path: '/webMMJ/keyDestruction', name: '密钥销毁', component: '@/pages/GLQ/WebMMJ/KeyDestruction' },
{ path: '/webMMJ/keyRemoteKill', name: '密钥遥毙', component: '@/pages/GLQ/WebMMJ/KeyRemoteKill' },
{ path: '/webMMJ/mmjRemoteKill', name: 'MMJ遥毙', component: '@/pages/GLQ/WebMMJ/MmjRemoteKill' },
// ---------------------------------------------------------------------------
// ------------------------------网络GLQ配置----------------------------------
// 获取配置信息
{ path: '/webGLQ/serviceListInfo', name: '服务列表信息', component: '@/pages/GLQ/WebGLQ/ServiceListInfo' },
{ path: '/webGLQ/networkConfigInfo', name: '网络配置信息', component: '@/pages/GLQ/WebGLQ/NetworkConfigInfo' },
{ path: '/webGLQ/securityPolicyInfo', name: '安全策略信息', component: '@/pages/GLQ/WebGLQ/SecurityPolicyInfo' },
{ path: '/webGLQ/manageConfigInfo', name: '管理配置信息', component: '@/pages/GLQ/WebGLQ/ManageConfigInfo' },
{ path: '/webGLQ/vpnPolicyInfo', name: 'VPN策略信息', component: '@/pages/GLQ/WebGLQ/VpnPolicyInfo' },
{ path: '/webGLQ/firewallPolicyInfo', name: '防火墙策略信息', component: '@/pages/GLQ/WebGLQ/FirewallPolicyInfo'},
{ path: '/webGLQ/logRecordInfo', name: '日志记录信息', component: '@/pages/GLQ/WebGLQ/LogRecordInfo' },
// 远程文件配置
{ path: '/webMMJ/serviceList', name: '服务列表', component: '@/pages/GLQ/WebGLQ/ServiceList' },
{ path: '/webMMJ/networkParams', name: '网络参数', component: '@/pages/GLQ/WebGLQ/NetworkParams' },
{ path: '/webMMJ/securityPolicy', name: '安全策略', component: '@/pages/GLQ/WebGLQ/SecurityPolicy' },
{ path: '/webMMJ/manageConfig', name: '管理配置', component: '@/pages/GLQ/WebGLQ/ManageConfig' },
{ path: '/webMMJ/vpnPolicy', name: 'VPN策略', component: '@/pages/GLQ/WebGLQ/VpnPolicy' },
// ---------------------------------------------------------------------------
// ------------------------------MY管理----------------------------------
// 密钥体管理
{ path: '/KeyBodyManage/formatImport', name: '密钥体格式导入', component: '@/pages/MY/KeyBodyManage/FormatImport' },
{ path: '/KeyBodyManage/formatPublishing', name: '密钥体格式发布', component: '@/pages/MY/KeyBodyManage/FormatPublishing' },
{ path: '/KeyBodyManage/application', name: '密钥体申请', component: '@/pages/MY/KeyBodyManage/Application' },
{ path: '/KeyBodyManage/import', name: '密钥体导入', component: '@/pages/MY/KeyBodyManage/Import' },
{ path: '/KeyBodyManage/receiptForm', name: '密钥体接收单', component: '@/pages/MY/KeyBodyManage/ReceiptForm' },
{ path: '/KeyBodyManage/cleaned', name: '已清理密钥体', component: '@/pages/MY/KeyBodyManage/Cleaned' },
{ path: '/KeyBodyManage/codeComparisonTable', name: '密钥体代号对照表', component: '@/pages/MY/KeyBodyManage/CodeComparisonTable' },
{ path: '/KeyBodyManage/subordinateDistr', name: '向下级配发', component: '@/pages/MY/KeyBodyManage/SubordinateDistr' },
{ path: '/KeyBodyManage/emailDistr', name: '向邮箱配发', component: '@/pages/MY/KeyBodyManage/EmailDistr' },
{ path: '/KeyBodyManage/systemDistr', name: '向专用密码管理系统配发', component: '@/pages/MY/KeyBodyManage/SystemDistr' },
{ path: '/KeyBodyManage/distrTriple', name: '密钥体配发三联单', component: '@/pages/MY/KeyBodyManage/DistrTriple' },
{ path: '/KeyBodyManage/plaintext', name: '明文载体包封', component: '@/pages/MY/KeyBodyManage/Plaintext' },
{ path: '/KeyBodyManage/ciphertext', name: '密文载体包封', component: '@/pages/MY/KeyBodyManage/Ciphertext' },
// 密钥管理
{ path: '/KeyManage/dataMaintenance', name: '管理系统管理盘数据维护', component: '@/pages/MY/KeyManage/DataMaintenance' },
{ path: '/KeyManage/relationConfig', name: '统型完善普密设备密钥互通关系配置', component: '@/pages/MY/KeyManage/RelationConfig' },
{ path: '/KeyManage/manageKeys', name: '管理密钥装配', component: '@/pages/MY/KeyManage/ManageKeys' },
{ path: '/KeyManage/userKey', name: '用户密钥装配', component: '@/pages/MY/KeyManage/UserKey' },
{ path: '/KeyManage/privateKey', name: '专用密钥装配', component: '@/pages/MY/KeyManage/PrivateKey' },
{ path: '/KeyManage/keyConfigQuery', name: '密钥配置查询', component: '@/pages/MY/KeyManage/KeyConfigQuery' },
{ path: '/KeyManage/tripleKeyDistri', name: '密钥配发三联单', component: '@/pages/MY/KeyManage/TripleKeyDistri' },
// 邮箱管理
{ path: '/mailboxManage/index', name: '邮箱管理', component: '@/pages/MY/MailboxManage/index' },
// ---------------------------------------------------------------------------
// ------------------------------SB管理----------------------------------
// 设备管理
{ path: '/deviceManage/dutyAreaConfig', name: '执勤区配置', component: '@/pages/SB/DeviceManage/DutyAreaConfig' },
{ path: '/deviceManage/dataSync', name: '数据同步', component: '@/pages/SB/DeviceManage/DataSync' },
{ path: '/deviceManage/remoteMaintenance', name: '远程维护', component: '@/pages/SB/DeviceManage/RemoteMaintenance' },
{ path: '/deviceManage/numberMaintenance', name: '报号维护', component: '@/pages/SB/DeviceManage/NumberMaintenance' },
// 日志管理
{ path: '/logManage/index', name: '日志管理', component: '@/pages/SB/LogManage/index' },
// 审计管理
{ path: '/auditManage/index', name: '审计管理', component: '@/pages/SB/AuditManage/index' },
// 境外任务管理
{ path: '/overseasTaskManage/index', name: '境外任务管理', component: '@/pages/SB/OverseasTaskManage/index' },
// ---------------------------------------------------------------------------
// ------------------------------SF管理----------------------------------
// 算法资源管理
{ path: '/resourceManage/algorithmMaintenance', name: '算法信息维护', component: '@/pages/SF/ResourceManage/AlgorithmMaintenance' },
{ path: '/resourceManage/paramMaintenance', name: '参数信息维护', component: '@/pages/SF/ResourceManage/ParamMaintenance' },
{ path: '/resourceManage/algorithmSetConfig', name: '算法集合配置', component: '@/pages/SF/ResourceManage/AlgorithmSetConfig' },
{ path: '/resourceManage/networkConfig', name: '管理类参数所属网络配置', component: '@/pages/SF/ResourceManage/NetworkConfig' },
{ path: '/resourceManage/algorithmDistr', name: '算法配发', component: '@/pages/SF/ResourceManage/AlgorithmDistr' },
{ path: '/resourceManage/algorithmParam', name: '算法参数配发', component: '@/pages/SF/ResourceManage/AlgorithmParam' },
// 算法配置管理
{ path: '/configManage/sfSingleInstallConfig', name: '单算法安装配置', component: '@/pages/SF/ConfigManage/SFSingleInstallConfig' },
{ path: '/configManage/sfSingleChangeConfig', name: '单算法更换配置', component: '@/pages/SF/ConfigManage/SFSingleChangeConfig' },
{ path: '/configManage/sfMultiInstallConfig', name: '多算法安装配置', component: '@/pages/SF/ConfigManage/SFMultiInstallConfig' },
{ path: '/configManage/sfMultiChangeConfig', name: '多算法更换配置', component: '@/pages/SF/ConfigManage/SFMultiChangeConfig' },
{ path: '/configManage/paramSingleInstallConfig', name: '单参数安装配置', component: '@/pages/SF/ConfigManage/ParamSingleInstallConfig' },
{ path: '/configManage/paramSingleChangeConfig', name: '单参数更换配置', component: '@/pages/SF/ConfigManage/ParamSingleChangeConfig' },
{ path: '/configManage/paramMultiInstallConfig', name: '多参数安装配置', component: '@/pages/SF/ConfigManage/ParamMultiInstallConfig' },
{ path: '/configManage/paramMultiChangeConfig', name: '多参数更换配置', component: '@/pages/SF/ConfigManage/ParamMultiChangeConfig' },
// 算法托收管理
{ path: '/collectionManage/dataSync', name: '算法托收管理', component: '@/pages/SF/CollectionManage/index' },
// 算法邮箱管理
{ path: '/mailboxManage/index', name: '算法邮箱管理', component: '@/pages/SF/MailboxManage/index' },
// ---------------------------------------------------------------------------
// ------------------------------SBJK二维版-----------------------------------
// ---------------------------------------------------------------------------
// ------------------------------设备注册-----------------------------------
// 注册管理
{ path: '/registerManage/deviceRegister/:id', name: '设备注册管理', component: '@/pages/Register/RegisterManage/DeviceRegister' },
{ path: '/registerManage/manageDiskMainten', name: '管理盘维护', component: '@/pages/Register/RegisterManage/ManageDiskMainten' },
{ path: '/registerManage/devicePhotoMainten', name: '设备照片维护', component: '@/pages/Register/RegisterManage/DevicePhotoMainten' },
{ path: '/registerManage/deviceSearch', name: '设备查找', component: '@/pages/Register/RegisterManage/DeviceSearch' },
{ path: '/registerManage/appSystemConfig', name: '应用系统配置', component: '@/pages/Register/RegisterManage/AppSystemConfig' },
{ path: '/registerManage/infoAggre', name: '信息汇总', component: '@/pages/Register/RegisterManage/InfoAggre' },
// 位置管理
{ path: '/registerManage/unitLocation/:id', name: '单位位置管理', component: '@/pages/Register/PositionManage/UnitLocation' },
{ path: '/registerManage/regionalEdit', name: '地域编辑', component: '@/pages/Register/PositionManage/RegionalEdit' },
// ---------------------------------------------------------------------------
// 建设中页面
{
path: '/construction',
component: '@/pages/construction'
},
{
path: '*',
component: '@/pages/404',
layout: false
}
]
export default routes;

22744
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,26 @@
{
"private": true,
"author": "鲁誉程 <2659568239@qq.com>",
"scripts": {
"dev": "umi dev",
"build": "umi build",
"postinstall": "umi setup",
"setup": "umi setup",
"start": "npm run dev"
},
"dependencies": {
"antd": "^5.11.2",
"body-parser": "^1.20.2",
"dayjs": "^1.11.10",
"dva": "^2.4.1",
"express": "^4.18.2",
"moment": "^2.29.4",
"umi": "^4.0.88"
},
"devDependencies": {
"@types/cors": "^2.8.17",
"@types/react": "^18.0.33",
"@types/react-dom": "^18.0.11",
"typescript": "^5.0.3"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 749 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 547 KiB

@ -0,0 +1,48 @@
.btn {
height: 32px;
// width: 112px;
padding: 0px 20px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.confirm_btn {
background: linear-gradient(180deg, #87CDEE 0%, #69C0E9 34%, #7ECDF2 51%, #56B9E6 63%, #81D7FE 100%);
box-shadow: 0px 1px 4px 0px rgba(81, 84, 90, 0.5);
border-radius: 4px;
border: 1px solid rgba(76, 106, 118, 0.22);
color: #fff;
}
.cancel_btn {
background: linear-gradient(180deg, #E3F6FF 0%, #F3FBFF 37%, #FFFFFF 51%, #EBF9FF 60%, #FFFFFF 100%);
box-shadow: 0px 1px 4px 0px rgba(81, 84, 90, 0.5);
border-radius: 4px;
border: 1px solid rgba(171, 207, 223, 0.22);
color: #65686E;
}
.delete_btn {
background: linear-gradient(180deg, #FFE5C5 0%, #FFE1B4 30%, #FCEED7 52%, #FFDC9B 73%, #F8E7C5 100%);
box-shadow: 0px 1px 4px 0px rgba(81, 84, 90, 0.5);
border-radius: 4px;
border: 1px solid #C2BFB8;
color: #65686E;
}
.special_btn {
background: linear-gradient(rgb(244, 251, 255) 0%, rgb(207, 233, 246) 100%);
box-shadow: 0px 1px 1px 0px rgba(177, 197, 218, 0.5);
border-radius: 4px;
border: 1px solid #D0DAE7;
font-size: 16px;
color: #333333;
padding: 0 30px;
cursor: default;
}
.disabled {
cursor: no-drop;
}

@ -0,0 +1,65 @@
import React, { FC, useEffect, useState } from 'react';
import styles from './index.less';
import { LoadingOutlined } from '@ant-design/icons';
import { Spin } from 'antd';
interface PageProps {
type?: string; // 按钮类型
text?: string; // 按钮文字
disabled?: boolean; // 按钮禁用
style?: any; //样式
loading?: boolean; // 加载中
onClick?: () => void;
}
// 按钮类型有以下几种confirm确认, cancel取消, delete(删除), special(特殊)
const ButtonComp: FC<PageProps> = ({
type = 'confirm',
text = '确定',
disabled = false,
style = {},
loading = false,
onClick = () => {},
}) => {
const [isLoading, setIsLoading] = useState(loading);
useEffect(() => {
setIsLoading(loading);
}, [loading]);
const click = () => {
if (disabled || isLoading) return;
const timerId = setTimeout(() => {
onClick();
}, 300);
return () => clearTimeout(timerId);
};
const buttonStyle = {
opacity: isLoading ? 0.8 : 1,
...style,
};
return (
<div style={{ display: 'flex' }}>
<div
style={buttonStyle}
className={`${styles.btn} ${styles[type + '_btn']} ${disabled ? styles.disabled : ''}`}
onClick={click}
>
{isLoading ? (
<>
<Spin size="small" style={{ color: '#fff', marginRight: 10 }} indicator={<LoadingOutlined spin />} />
<span>{`${text}`}</span>
</>
) : (
text
)}
</div>
</div>
);
};
export default ButtonComp;

@ -0,0 +1,40 @@
import { FC } from 'react';
import { Modal } from 'antd';
import ButtonComp from '../ButtonComp';
interface PageProps {
title?: string;
visibility: boolean;
onCancel: () => void;
onOk: () => void;
children?: any; // 插槽内容
}
const ClearInfoDialog: FC<PageProps> = ({
title = "提示",
visibility = false,
onCancel,
onOk,
...props
}) => {
return (
<Modal
title={title}
open={visibility}
centered
width={420}
onCancel={onCancel}
footer={null}
maskClosable={false}
>
{props?.children}
<div className='flex_jE mt20'>
<ButtonComp style={{ marginRight: 20 }} text={'确定'} onClick={onOk} />
<ButtonComp type="cancel" text={'取消'} onClick={onCancel} />
</div>
</Modal>
)
}
export default ClearInfoDialog

@ -0,0 +1,25 @@
.cont_warp {
position: relative;
background: #FFFFFF;
border-radius: 2px 0px 0px 0px;
border: 1px solid #D8D8D8;
margin-top: 8px;
padding-top: 25px;
.cont_warp_title {
position: absolute;
top: -8px;
left: -1px;
padding: 0 30px;
height: 32px;
line-height: 32px;
background: linear-gradient(180deg, #F4FBFF 0%, #CFE9F6 100%);
border-radius: 4px 4px 4px 0px;
border: 1px solid #D0DAE7;
cursor: default;
font-size: 16px;
font-weight: 400;
color: #333333;
}
}

@ -0,0 +1,24 @@
import { FC, useEffect, useState } from 'react';
import styles from './index.less';
interface PageProps {
style?: any; // 样式
text: any; // 标题区域
children?: any; // 插槽内容
}
const ContentWarp: FC<PageProps> = ({
style,
text,
...props
}) => {
return (
<div className={styles.cont_warp} style={style}>
<div className={styles.cont_warp_title}>{text}</div>
{props?.children}
</div>
)
}
export default ContentWarp

@ -0,0 +1,42 @@
import { FC, useRef } from 'react';
import ButtonComp from '../ButtonComp';
interface PageProps {
domId: string; // 元素id
fileName?: string; // 文件名称
btnName?: string; // 按钮名称
style?: any;
}
const SaveAs: FC<PageProps> = ({
domId,
fileName = '文件名称',
btnName = '文件另存',
style
}) => {
const downloadLink: any = useRef(null);
const saveAs = () => {
const element: any = document.getElementById(domId);
const text = element.innerText || element.textContent;
// 创建一个Blob对象保存文本内容
const blob = new Blob([text], { type: 'text/plain' });
// 设置下载链接的href和download属性
downloadLink.current.href = URL.createObjectURL(blob);
downloadLink.current.download = fileName;
// 点击下载链接
downloadLink.current.click();
// 释放下载链接
URL.revokeObjectURL(downloadLink.current.href);
}
return (
<div style={{...style}}>
<a ref={downloadLink} style={{ display: 'none' }} />
<ButtonComp type={'cancel'} text={btnName} onClick={() => saveAs()} />
</div>
)
}
export default SaveAs

@ -0,0 +1,37 @@
.tabs {
width: 100%;
height: 36px;
display: flex;
align-items: center;
margin-bottom: 20px;
font-size: 14px;
.item_tab,
.active_tab {
font-size: 14px;
font-weight: 400;
margin-right: 50px;
cursor: pointer;
display: flex;
align-items: center;
}
.active_tab {
font-weight: 600;
}
.item_tab {
color: #333;
&:hover {
font-weight: 600;
}
}
.active_line {
position: absolute;
width: 100%;
height: 4px;
background: linear-gradient(180deg, #FFFFFF 0%, #3F9DC8 100%);
top: 21px;
}
}

@ -0,0 +1,34 @@
import { FC, useEffect, useState } from 'react';
import styles from './index.less';
interface PageProps {
dataSource: { id: string | number; name: string }[]; // tabs
activeTab: number; // 当前选中的tab
onChange: (id: any) => void;
}
const TabsComp: FC<PageProps> = ({ dataSource, activeTab, onChange }) => {
return (
<div className={styles.tabs}>
{dataSource.map((item: any, i: number) => {
return (
<div
key={i}
className={`${activeTab == item.id ? styles.active_tab : styles.item_tab}`}
onClick={() => {
if (item.id == activeTab) return;
onChange(item.id);
}}
>
<div style={{ position: 'relative' }}>
{item.name}
<div className={`${activeTab == item.id ? styles.active_line : ''}`}></div>
</div>
</div>
)
})}
</div>
)
}
export default TabsComp

@ -0,0 +1,23 @@
@import './styles/reset.less';
@import './styles/minix.less';
@import './styles/antd.less';
::-webkit-scrollbar {
height: 3px;
width: 3px;
background: rgba(0, 0, 0, 0.1) !important;
}
::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.1) !important;
border-radius: 3px;
&:hover {
background: rgba(0, 0, 0, 0.20) !important;
}
}
::-webkit-scrollbar-track {
background-color: #f6f7f94d !important;
box-shadow: initial !important;
}

@ -0,0 +1,45 @@
.bottom_warp {
width: 100%;
height: 140px;
background: #FFFFFF;
border-radius: 2px 0px 0px 0px;
border-top: 1px solid #D8D8D8;
display: flex;
align-items: center;
justify-content: space-between;
.item_con {
width: 50%;
height: 100%;
display: flex;
._img {
width: 54px;
height: 54px;
margin: 20px;
background-color: saddlebrown;
}
.item_info {
&:nth-child(2),
&:nth-child(3) {
height: 22px;
font-size: 14px;
font-weight: 400;
color: #333333;
line-height: 22px;
}
}
.item_title {
margin-top: 34px;
height: 26px;
line-height: 26px;
font-size: 16px;
font-weight: 600;
color: #333333;
margin-bottom: 10px;
}
}
}

@ -0,0 +1,31 @@
import { FC, useEffect, useState } from 'react';
import styles from './index.less';
interface PageProps {
}
const BottomConfigInfo: FC<PageProps> = ({}) => {
return (
<div className={styles.bottom_warp}>
<div className={styles.item_con}>
<div className={styles._img}></div>
<div className={styles.item_info}>
<div className={styles.item_title}></div>
<div style={{ marginBottom: 6 }}>--</div>
<div>IP--</div>
</div>
</div>
<div className={styles.item_con}>
<div className={styles._img}></div>
<div className={styles.item_info}>
<div className={styles.item_title}></div>
<div style={{ marginBottom: 6 }}>--</div>
<div>--</div>
</div>
</div>
</div>
)
}
export default BottomConfigInfo

@ -0,0 +1,52 @@
.menu_item {
width: 260px;
height: 32px;
background: linear-gradient(180deg, #4AB4E4 0%, #A2E1FF 100%);
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: 600;
color: #FFFFFF;
cursor: pointer;
position: relative;
.triangle {
position: absolute;
right: 20px;
width: 0;
height: 0;
border-left: 6px solid #fff;
border-bottom: 6px solid transparent;
border-top: 6px solid transparent;
transition: all 0.15s ease-in;
}
}
.item_warp {
transition: all 2s ease-in;
.item1 {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
margin: 20px 0;
cursor: pointer;
}
.item1_img {
width: 60px;
height: 60px;
background-color: saddlebrown;
}
.item1_name {
width: 100%;
text-align: center;
font-size: 14px;
font-weight: 400;
color: #1A374A;
margin-top: 6px;
}
}

@ -0,0 +1,206 @@
import { FC, useEffect, useRef, useState } from 'react';
import styles from './index.less';
import { history, useLocation, useParams } from 'umi';
import { Menu, Tree } from 'antd';
interface PageProps {
data: Array<{
// 菜单名称
name: string;
// 是否展开
check: boolean;
// 内容是否有目录结构
isTree?: boolean;
// 菜单列表 name: 名称; url: 路由; img: 图标;
data: Array<{ name: string; url: string; img: any; }>
}>;
}
const LeftMenuCom: FC<PageProps> = ({ data }) => {
const [list, setList] = useState<any>([]);
const route = useLocation();
const urlParams = useParams();
const [selectedKeys, setSelectedKeys] = useState<any>([]);
const [contextMenuPosition, setContextMenuPosition] = useState({ x: 0, y: 0 });
const [showContextMenu, setShowContextMenu] = useState(false);
const treeRef = useRef(null);
const [menuItems, setMenuItems] = useState<any>([]);
useEffect(() => {
menuItemsConfig();
data.forEach((item, index) => {
// 默认展开第一个
// item.check = (index == 0 ? true : false);
// 默认全部展开
item.check = true;
if (item?.isTree) setSelectedKeys([urlParams?.id])
})
setList([...data])
const handleClickOutside = (e: any) => {
if (treeRef.current && !treeRef.current.contains(e.target)) {
// 点击了 MyTree 组件以外的地方,隐藏菜单
setShowContextMenu(false);
}
};
document.addEventListener('click', handleClickOutside);
return () => {
document.removeEventListener('click', handleClickOutside);
};
}, [])
const menuItemsConfig = () => {
if (`/registerManage/deviceRegister/${urlParams?.id}` == route?.pathname) {
setMenuItems([
{key: '1', label: '删除'},
{key: '2', label: '刷新'},
])
}else if (`/registerManage/unitLocation/${urlParams?.id}` == route?.pathname) {
setMenuItems([
{key: '1', label: '修改'},
{key: '2', label: '刷新'},
{key: '3', label: '新建'},
{key: '4', label: '删除'}
])
}
}
const handleRightClick = (e: any, node: any) => {
if (node?.isFolder) return
e.preventDefault();
setContextMenuPosition({ x: e.clientX, y: e.clientY }); // 记录右键菜单位置
setSelectedKeys([node.key]); // 根据节点设置选中的 keys
setShowContextMenu(true); // 显示右键菜单
};
const handleSelect = (selectedKeys: any, name: any) => {
if (selectedKeys.length == 0) return;
setSelectedKeys(selectedKeys);
switch (name) {
case '设备注册':
history.push(`/registerManage/deviceRegister/${selectedKeys[0]}`)
break;
case '单位位置管理':
history.push(`/registerManage/unitLocation/${selectedKeys[0]}`)
break;
}
};
const handleContextMenuClick = (e: any) => {
setShowContextMenu(false); // 隐藏右键菜单
};
const treeData = [
{
title: 'Parent 1',
key: '0-1',
selectable: false,
isFolder: true,
children: [
{
title: 'Child 1',
key: '0-1-1',
},
{
title: 'Child 2',
key: '0-1-2',
},
],
},
{
title: 'Parent 2',
key: '0-2',
selectable: false,
isFolder: true,
children: [
{
title: 'Child 3',
key: '0-2-1',
},
{
title: 'Child 4',
key: '0-2-2',
},
],
},
];
return (
<div>
{list.map((item: any, index: number) => {
return (
<div key={index}>
{/* 类型 */}
<div className={styles.menu_item} onClick={() => {
list[index].check = !list[index].check;
setList([...list])
}}>
<div>{item.name}</div>
<div className={styles.triangle} style={{ transform: list[index].check ? 'rotate(90deg)' : '' }}></div>
</div>
{/* 列表 */}
<div className={styles.item_warp} style={{ display: list[index].check ? 'block' : 'none' }}>
{
item?.isTree ?
// 树结构
<div>
<Tree
style={{ padding: 20 }}
onContextMenu={(e) => e.preventDefault()}
onRightClick={({ event, node }) => handleRightClick(event, node)}
onSelect={(e) => { handleSelect(e, item.name) }}
selectedKeys={selectedKeys}
treeData={treeData}
blockNode={true}
defaultExpandAll={true}
/>
{showContextMenu && (
<div ref={treeRef}>
<Menu
style={{
zIndex: 99,
width: 111,
position: 'absolute',
left: contextMenuPosition.x,
top: contextMenuPosition.y,
boxShadow: '0px 4px 8px 0px rgba(156, 172, 180, 0.5)'
}}
mode="vertical"
onClick={handleContextMenuClick}
items={menuItems}
/>
</div>
)}
</div> :
// 列表item
item.data.map((item1: any, index1: number) => {
return (
<div className={styles.item1} key={index1} onClick={() => {
setSelectedKeys([])
history.push(item1.url)
}}>
<div className={styles.item1_img}></div>
<div className={styles.item1_name} style={{ color: (route.pathname == item1.url ? 'red' : '') }}>
{item1.name}
</div>
</div>
)
})
}
</div>
</div>
)
})}
</div >
)
}
export default LeftMenuCom

@ -0,0 +1,52 @@
.menu_item {
width: 260px;
height: 32px;
background: linear-gradient(180deg, #4AB4E4 0%, #A2E1FF 100%);
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: 600;
color: #FFFFFF;
cursor: pointer;
position: relative;
.triangle {
position: absolute;
right: 20px;
width: 0;
height: 0;
border-left: 6px solid #fff;
border-bottom: 6px solid transparent;
border-top: 6px solid transparent;
transition: all 0.15s ease-in;
}
}
.item_warp {
transition: all 2s ease-in;
.item1 {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
margin: 20px 0;
cursor: pointer;
}
.item1_img {
width: 60px;
height: 60px;
background-color: saddlebrown;
}
.item1_name {
width: 100%;
text-align: center;
font-size: 14px;
font-weight: 400;
color: #1A374A;
margin-top: 6px;
}
}

@ -0,0 +1,206 @@
import { FC, useEffect, useRef, useState } from 'react';
import styles from './index.less';
import { history, useLocation, useParams } from 'umi';
import { Menu, Tree } from 'antd';
interface PageProps {
data: Array<{
// 菜单名称
name: string;
// 是否展开
check: boolean;
// 内容是否有目录结构
isTree?: boolean;
// 菜单列表 name: 名称; url: 路由; img: 图标;
data: Array<{ name: string; url: string; img: any; }>
}>;
}
const LeftMenuCom: FC<PageProps> = ({ data }) => {
const [list, setList] = useState<any>([]);
const route = useLocation();
const urlParams = useParams();
const [selectedKeys, setSelectedKeys] = useState<any>([]);
const [contextMenuPosition, setContextMenuPosition] = useState({ x: 0, y: 0 });
const [showContextMenu, setShowContextMenu] = useState(false);
const treeRef = useRef(null);
const [menuItems, setMenuItems] = useState<any>([]);
useEffect(() => {
menuItemsConfig();
data.forEach((item, index) => {
// 默认展开第一个
// item.check = (index == 0 ? true : false);
// 默认全部展开
item.check = true;
if (item?.isTree) setSelectedKeys([urlParams?.id])
})
setList([...data])
const handleClickOutside = (e: any) => {
if (treeRef.current && !treeRef.current.contains(e.target)) {
// 点击了 MyTree 组件以外的地方,隐藏菜单
setShowContextMenu(false);
}
};
document.addEventListener('click', handleClickOutside);
return () => {
document.removeEventListener('click', handleClickOutside);
};
}, [])
const menuItemsConfig = () => {
if (`/registerManage/deviceRegister/${urlParams?.id}` == route?.pathname) {
setMenuItems([
{key: '1', label: '删除'},
{key: '2', label: '刷新'},
])
}else if (`/registerManage/unitLocation/${urlParams?.id}` == route?.pathname) {
setMenuItems([
{key: '1', label: '修改'},
{key: '2', label: '刷新'},
{key: '3', label: '新建'},
{key: '4', label: '删除'}
])
}
}
const handleRightClick = (e: any, node: any) => {
if (node?.isFolder) return
e.preventDefault();
setContextMenuPosition({ x: e.clientX, y: e.clientY }); // 记录右键菜单位置
setSelectedKeys([node.key]); // 根据节点设置选中的 keys
setShowContextMenu(true); // 显示右键菜单
};
const handleSelect = (selectedKeys: any, name: any) => {
if (selectedKeys.length == 0) return;
setSelectedKeys(selectedKeys);
switch (name) {
case '设备注册':
history.push(`/registerManage/deviceRegister/${selectedKeys[0]}`)
break;
case '单位位置管理':
history.push(`/registerManage/unitLocation/${selectedKeys[0]}`)
break;
}
};
const handleContextMenuClick = (e: any) => {
setShowContextMenu(false); // 隐藏右键菜单
};
const treeData = [
{
title: 'Parent 1',
key: '0-1',
selectable: false,
isFolder: true,
children: [
{
title: 'Child 1',
key: '0-1-1',
},
{
title: 'Child 2',
key: '0-1-2',
},
],
},
{
title: 'Parent 2',
key: '0-2',
selectable: false,
isFolder: true,
children: [
{
title: 'Child 3',
key: '0-2-1',
},
{
title: 'Child 4',
key: '0-2-2',
},
],
},
];
return (
<div>
{list.map((item: any, index: number) => {
return (
<div key={index}>
{/* 类型 */}
<div className={styles.menu_item} onClick={() => {
list[index].check = !list[index].check;
setList([...list])
}}>
<div>{item.name}</div>
<div className={styles.triangle} style={{ transform: list[index].check ? 'rotate(90deg)' : '' }}></div>
</div>
{/* 列表 */}
<div className={styles.item_warp} style={{ display: list[index].check ? 'block' : 'none' }}>
{
item?.isTree ?
// 树结构
<div>
<Tree
style={{ padding: 20 }}
onContextMenu={(e) => e.preventDefault()}
onRightClick={({ event, node }) => handleRightClick(event, node)}
onSelect={(e) => { handleSelect(e, item.name) }}
selectedKeys={selectedKeys}
treeData={treeData}
blockNode={true}
defaultExpandAll={true}
/>
{showContextMenu && (
<div ref={treeRef}>
<Menu
style={{
zIndex: 99,
width: 111,
position: 'absolute',
left: contextMenuPosition.x,
top: contextMenuPosition.y,
boxShadow: '0px 4px 8px 0px rgba(156, 172, 180, 0.5)'
}}
mode="vertical"
onClick={handleContextMenuClick}
items={menuItems}
/>
</div>
)}
</div> :
// 列表item
item.data.map((item1: any, index1: number) => {
return (
<div className={styles.item1} key={index1} onClick={() => {
setSelectedKeys([])
history.push(item1.url)
}}>
<div className={styles.item1_img}></div>
<div className={styles.item1_name} style={{ color: (route.pathname == item1.url ? 'red' : '') }}>
{item1.name}
</div>
</div>
)
})
}
</div>
</div>
)
})}
</div >
)
}
export default LeftMenuCom

@ -0,0 +1,23 @@
.item1 {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
margin: 20px 0;
cursor: pointer;
}
.item1_img {
width: 60px;
height: 60px;
background-color: saddlebrown;
}
.item1_name {
width: 100%;
text-align: center;
font-size: 14px;
font-weight: 400;
color: #1A374A;
margin-top: 6px;
}

@ -0,0 +1,42 @@
import { FC, useEffect, useState } from 'react';
import { history, useLocation } from "umi";
import styles from './index.less';
interface PageProps {
data: Array<{
// 名称
name: string;
// 路由
url: string;
// 图标
img: any;
}>
}
const LeftMenuCom: FC<PageProps> = ({ data }) => {
const [list, setList] = useState<any>([]);
const route = useLocation();
useEffect(() => {
setList([...data])
}, [])
return (
<div>
{list.map((item: any, index: number) => {
return (
<div className={styles.item1} key={index} onClick={() => history.push(item.url)}>
<div className={styles.item1_img}></div>
<div className={styles.item1_name} style={{color: (route.pathname == item.url ? 'red' : '')}}>
{item.name}
</div>
</div>
)
})}
</div>
)
}
export default LeftMenuCom

@ -0,0 +1,199 @@
#layout_main {
width: 100%;
height: 100vh;
min-width: 1440px;
min-height: 100vh;
transition: all ease 2s;
font-size: 14px;
.nav_warp {
width: 100%;
height: auto;
user-select: none;
.nav_warp_t,
.logo_warp,
.menu_list {
display: flex;
align-items: center;
}
.nav_warp_t {
width: 100%;
height: 92px;
background: linear-gradient(180deg, #F7FCFF 0%, #ECF7FF 100%);
justify-content: space-between;
}
.logo_icon {
width: 46px;
height: 46px;
background-color: saddlebrown;
margin: 0 10px 0 20px;
}
.system_title {
font-size: 24px;
font-weight: 600;
color: #4A6B89;
letter-spacing: 2px;
}
.menu_list {
margin-right:200px;
&_item {
&_img {
width: 50px;
height: 50px;
background-color: saddlebrown;
margin-right: 40px;
cursor: pointer;
}
&_name {
font-size: 14px;
font-weight: 400;
color: #1A374A;
margin-top: 6px;
}
.name_active{
color:#E30000;
}
}
}
.times {
margin-right: 20px;
font-size: 12px;
div {
height: 20px;
line-height: 20px;
color: #666666;
margin-bottom: 4px;
}
}
.nav_warp_b {
display:flex;
align-items: center;
justify-content: space-between;
background: linear-gradient(rgb(74, 180, 228) 0%, rgb(162, 225, 255) 100%);
box-shadow: 0px 2px 4px 0px rgba(36, 57, 75, 0.5);
&_version{
margin-left:20px;
}
&_menu {
display: flex;
height: 40px;
.tab_warp {
padding: 0 30px;
display: flex;
justify-content: center;
position: relative;
overflow: hidden;
&:not(:last-child)::after {
position: absolute;
right: 0;
top: 50%;
bottom: 50%;
transform: translateY(-50%);
content: '';
height: 28px;
border-right: 1px solid rgba(217, 217, 217, .55);
height: 28px;
}
}
.tab_con {
width: auto;
padding: 0 44px;
border: 1px solid rgba(0, 0, 0, 0);
margin-top: 4px;
font-size: 16px;
font-weight: 600;
color: #fff;
cursor: pointer;
border-radius: 4px 4px 0px 0px;
display: flex;
padding-top: 8px;
&:hover {
border: 1px solid #fff;
background: linear-gradient(180deg, #CAE9F7 0%, #FFFFFF 100%);
color: #4A6B89;
}
}
.active_tab {
border: 1px solid #fff;
background: linear-gradient(180deg, #CAE9F7 0%, #FFFFFF 100%);
color: #4A6B89;
}
}
}
.nav_warp_sub{
width:100%;
height:40px;
line-height:40px;
text-align:center;
color: #4A6B89;
font-size:16px;
font-weight: 600;
background: linear-gradient(180deg, #CAE9F7 0%, #FFFFFF 100%);
}
}
.main_warp {
width: 100%;
height: calc(100vh - 114px);
min-height: 600px;
display: flex;
.left_menu {
width: 260px;
min-width: 260px;
height: 100%;
min-height: calc(100vh - 114px - 50px);
background: #FFFFFF;
border-right: 1px solid #D8D8D8;
overflow: hidden;
overflow-y: auto;
user-select: none;
}
.right_warp {
height: calc(100% - 114px);
min-height: calc(100vh - 114px);
width: calc(100% - 261px)
}
.right_route {
position: relative;
overflow: hidden;
overflow-y: auto;
background: #F9F9F9;
}
}
.footer {
display: flex;
align-items: center;
justify-content: space-between;
color: #fff;
font-size: 14px;
padding: 0 20px;
height: 50px;
background: linear-gradient(180deg, #BEE5F8 0%, #4AB4E4 100%);
box-shadow: 0px -2px 4px 0px rgba(199, 206, 213, 0.5);
border-radius: 1px;
border: 2px solid;
border-image: linear-gradient(180deg, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0)) 2 2;
}
}

@ -0,0 +1,294 @@
import { Outlet, history, useLocation } from 'umi';
import styles from './index.less';
import { useEffect, useState } from 'react';
import { MenuType, tabsType } from '@/utils/menu';
import { ConfigProvider, Select, message } from 'antd';
import LeftMenuOne from '@/layouts/LeftMenuOne';
import LeftMenuTwo from '@/layouts/LeftMenuTwo';
import BottomConfigInfo from '@/layouts/BottomConfigInfo';
import zhCN from 'antd/es/locale/zh_CN';
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
import theme from '@/styles/antd.theme';
dayjs.locale('zh-cn');
import moment from 'moment'
moment.locale('ZH-cn')
const options2 = [
{ value: 1, label: 'GLQ管理' },
{ value: 2, label: 'MY管理' },
{ value: 3, label: 'SB管理' },
{ value: 4, label: 'SF管理' },
{ value: 5, label: 'SBJK二维版', disabled: true },
{ value: 6, label: '设备注册' }
]
const leftMenuType: any = {
// GLQ管理
'GLQ远程维护': <LeftMenuOne key={1} data={MenuType['GLQ远程维护']} />,
'网络MMJ管理': <LeftMenuTwo key={2} data={MenuType['网络MMJ管理']} />,
'网络GLQ配置': <LeftMenuOne key={3} data={MenuType['网络GLQ配置']} />,
// MY管理
'密钥体管理': <LeftMenuOne key={4} data={MenuType['密钥体管理']} />,
'密钥管理': <LeftMenuOne key={5} data={MenuType['密钥管理']} />,
'邮箱管理': <LeftMenuOne key={6} data={MenuType['邮箱管理']} />,
// SB管理
'设备管理': <LeftMenuOne key={7} data={MenuType['设备管理']} />,
'日志管理': <LeftMenuTwo key={8} data={MenuType['日志管理']} />,
'审计管理': <LeftMenuTwo key={9} data={MenuType['审计管理']} />,
'境外任务管理': <LeftMenuTwo key={10} data={MenuType['境外任务管理']} />,
// SF管理
'算法资源管理': <LeftMenuOne key={11} data={MenuType['算法资源管理']} />,
'算法配置管理': <LeftMenuOne key={12} data={MenuType['算法配置管理']} />,
'算法托收管理': <LeftMenuOne key={13} data={MenuType['算法托收管理']} />,
'算法邮箱管理': <LeftMenuOne key={14} data={MenuType['算法邮箱管理']} />,
// SBJK二维版
'设备监控二维版': <div />,
// 设备注册
'注册管理': <LeftMenuOne key={15} data={MenuType['注册管理']} />,
'位置管理': <LeftMenuOne key={16} data={MenuType['位置管理']} />
}
export default function Layout() {
const location = useLocation();
const [routeName, setRouteName] = useState<string>('');
const [selectVal, setSelectVal] = useState<number>(1);
const [tabList, setTabList] = useState<any>([]);
const [active, setActive] = useState<number>(1);
const [activeName, setActiveName] = useState<any>('GLQ远程维护');
const [treeData, setTreeData] = useState<any>([
{
title: 'Parent 1',
key: '0-1',
selectable: false,
isFolder: true,
children: [
{
title: 'Child 1',
key: '0-1-1',
},
{
title: 'Child 2',
key: '0-1-2',
},
],
},
{
title: 'Parent 2',
key: '0-2',
selectable: false,
isFolder: true,
children: [
{
title: 'Child 3',
key: '0-2-1',
},
{
title: 'Child 4',
key: '0-2-2',
},
],
},
]);
// 获取布局信息
let layoutInfo: any = localStorage.getItem('layoutInfo');
layoutInfo = JSON.parse(layoutInfo);
useEffect(() => {
// 校验浏览器是否有储存的布局信息
if (layoutInfo) {
setActive(layoutInfo.active);
setActiveName(layoutInfo.activeName);
setSelectVal(layoutInfo.selectVal);
setTabList([...tabsType[layoutInfo.selectVal]]);
} else {
setTabList([...tabsType[selectVal]]);
}
}, [])
useEffect(() => {
setRouteName(getCurrentPageName(location.pathname))
}, [location]);
// 页面销毁前记录下当前布局信息
window.addEventListener('beforeunload', function (event) {
let layoutInfo: any = {
selectVal: selectVal,
active: active,
activeName: activeName,
}
localStorage.setItem('layoutInfo', JSON.stringify(layoutInfo));
});
useEffect(() => {
// 条件判断: 当选择框的值发生改变时tabList长度大于0 并且 没有发现记录布局的数据)时 ,默认进入第一个模块的页面
if (tabList.length > 0 && !layoutInfo) {
setActiveName(tabList[0].name)
let info = MenuType[tabList[0].name];
if (isTreeType(info)) return
if (info[0].data) {
history.push(`${info[0].data[0].url}`)
} else {
history.push(`${info[0].url}`)
}
}
}, [selectVal])
// 校验是否是树结构列表
const isTreeType = (info: any) => {
if (info.length > 0) {
if (info[0]?.name === '设备注册') {
return navigateToPath(info, '/registerManage/deviceRegister/{key}');
}
if (info[0]?.name === '单位位置管理') {
return navigateToPath(info, '/registerManage/unitLocation/{key}');
}
}
return false;
};
// 前往对应的路由
const navigateToPath = (info: any, path: string) => {
const targetNode = treeData.find((node: any) => node.children.length > 0);
if (targetNode) {
history.push(path.replace('{key}', targetNode.children[0].key));
return true;
}
return false;
};
// 获取路由名称
const getCurrentPageName = (pathname: string) => {
const routes = require('../../config/routes/index').default;
const currentRoute = routes.find((route: any) => route.path === pathname);
return currentRoute?.name || '未知页面';
};
return (
<ConfigProvider
locale={zhCN}
autoInsertSpaceInButton={false}
componentSize="middle"
theme={theme}
>
<div id={styles.layout_main}>
{/* 顶部导航 */}
<div className={styles.nav_warp}>
<div className={styles.nav_warp_t}>
<div className={styles.logo_warp}>
<div className={styles.logo_icon}></div>
<div className={styles.system_title}>XXXX</div>
</div>
<div className={styles.menu_list}>
{
options2.map((item: any) => {
return <div
className={styles.menu_list_item}
onClick={() => {
// 点击一级路由时将布局信息清空
localStorage.setItem('layoutInfo', JSON.stringify(null));
setSelectVal(item.value)
setTabList([...tabsType[item.value]])
setActive(1)
}}
>
<div className={styles.menu_list_item_img}></div>
<div className={`${styles.menu_list_item_name} ${selectVal === item.value ? styles.name_active :''}`}>{item.label}</div>
</div>
})
}
</div>
</div>
<div className={styles.nav_warp_b}>
<div className={styles.nav_warp_b_version}>v1.2.0.0</div>
<div className={styles.nav_warp_b_menu}>
{
tabList.map((item: any, index: number) => {
return <div key={index} className={styles.tab_warp}>
<div className={`${styles.tab_con} ${(index + 1) == active ? styles.active_tab : ''}`}
onClick={() => {
let info = MenuType[item.name];
setActive(item.id)
setActiveName(item.name)
if (isTreeType(info)) return
if (info.length == 0 || info[0].data && info[0].data.length == 0) {
history.push('/construction');
return
}
// 改变activeName时跳转菜单栏的第一个路由
if (info[0].data) {
history.push(`${info[0].data[0].url}`)
} else {
history.push(`${info[0].url}`)
}
}}>
{item.name}
</div>
</div>
})
}
</div>
<div className={styles.times}>
<div>XXXX3023-00-00 15:00:00</div>
<div>XXXX3023-00-00 15:00:00</div>
</div>
</div>
{/* 二级导航标题 */}
<div className={styles.nav_warp_sub}>
<div>{activeName}</div>
</div>
</div>
{/* 主体内容 */}
<div className={styles.main_warp}>
{/* 左侧菜单栏 */}
<div className={styles.left_menu}>
{leftMenuType[activeName]}
</div>
{/* 右侧内容 */}
<div className={styles.right_warp}>
<div className={styles.right_route}
style={{
height: selectVal == 1 ?
'calc(100vh - 114px - 141px - 52px)' :
'calc(100vh - 114px - 52px)'
}}
>
<Outlet></Outlet>
</div>
{/* GQL管理整个模块页面底部的配置信息 */}
{selectVal == 1 && <BottomConfigInfo />}
</div>
</div>
{/* 底部信息 */}
<div className={styles.footer}>
<div></div>
<div>xxx</div>
<div>user</div>
<div style={{ minWidth: 180, textAlign: 'right' }}></div>
</div>
</div>
</ConfigProvider >
);
}

@ -0,0 +1,18 @@
import { history } from 'umi';
import { Button, Result } from 'antd';
import React from 'react';
const NoFoundPage: React.FC = () => (
<Result
status="404"
title="404"
subTitle="Sorry, the page you visited does not exist."
extra={
<Button type="primary" onClick={() => history.push('/')}>
Back Home
</Button>
}
/>
);
export default NoFoundPage;

@ -0,0 +1,62 @@
.entrance {
position: relative;
width: 100vw;
min-height: 100vh;
background: url('../../assets/images/bk_img.png') no-repeat;
background-size: 100% 100%;
.text_warp {
width: 80vw;
margin: 0 auto;
div {
text-align: center;
}
div:nth-child(1) {
font-size: 36px;
font-weight: 600;
padding-top: 30vh;
}
div:nth-child(2) {
font-size: 50px;
font-weight: 600;
margin: 50px 0 80px 0;
letter-spacing: 2px;
}
div:nth-child(3) {
font-size: 28px;
}
}
.prompt {
position: fixed;
bottom: 45px;
right: 20px;
font-size: 24px;
color: red;
font-weight: bold;
}
}
.login_warp {
display: flex;
align-items: center;
.imges {
width: 81px;
height: 81px;
margin-right: 20px;
background-color: saddlebrown;
}
}
.goback {
position: absolute;
left: 20px;
top: 20px;
font-size: 18px;
cursor: pointer;
}

@ -0,0 +1,91 @@
import { FC, useEffect, useState } from 'react';
import { history, useLocation } from "umi";
import styles from './index.less';
import { Input, Modal, message } from 'antd';
import ButtonComp from '@/components/ButtonComp';
import { LeftOutlined } from '@ant-design/icons';
interface PageProps { }
const CoreSystemEntrance: FC<PageProps> = ({ }) => {
const [visibility, setVisibility] = useState<boolean>(false);
const [key, setKey] = useState<string>('一');
const [pin, setPin] = useState<any>('');
useEffect(() => {
function handleKeyPress(e: any) {
if (e.key === 'Enter') {
setVisibility(true)
}
}
// 添加事件监听器
document.addEventListener('keydown', handleKeyPress);
// 清除事件监听器
return () => {
document.removeEventListener('keydown', handleKeyPress);
};
}, [])
const initData = () => {
setVisibility(false);
setKey('一');
setPin('')
}
const submit = () => {
if (key == '一' && pin == '123123') {
setKey('二');
setPin('')
} else if (key == '二' && pin == '123123') {
initData()
// 登录成功进入系统
history.push('/teamViewer/paramsSetting')
}else {
message.error('PIN码错误请重新输入')
}
}
return (
<div className={styles.entrance}>
<div className={styles.goback} onClick={() => history.push('/')}><LeftOutlined /></div>
<div className={styles.text_warp}>
<div></div>
<div></div>
<div></div>
</div>
<div className={styles.prompt}>...</div>
{/* 登录弹窗 */}
<Modal
title="用户登录pin码123123"
open={visibility}
centered
width={550}
onCancel={() => setVisibility(false)}
footer={null}
maskClosable={false}
>
<div className={styles.login_warp}>
<div className={styles.imges}></div>
<div>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ width: 120, marginRight: 16 }}>PIN</div>
<Input placeholder="请输入PIN码" value={pin} onChange={(e) => setPin(e.target.value)} onPressEnter={() => submit()} />
</div>
<div className='mt20'>{key}PIN</div>
</div>
</div>
<div className='flex_jE mt20'>
<ButtonComp style={{ marginRight: 20 }} text={'确定'} onClick={() => submit()} />
<ButtonComp type="cancel" text={'退出'} onClick={() => initData()} />
</div>
</Modal>
</div>
)
}
export default CoreSystemEntrance

@ -0,0 +1,10 @@
import styles from './index.less';
// GLQ远程维护 --> 交互维护命令--> 当前IP
export default function Page() {
return (
<div>
{'GLQ远程维护 --> 交互维护命令--> 当前IP'}
</div>
);
}

@ -0,0 +1,10 @@
import styles from './index.less';
// GLQ远程维护 --> 交互维护命令--> 当前IP
export default function Page() {
return (
<div>
{'GLQ远程维护 --> 交互维护命令--> 当前IP'}
</div>
);
}

@ -0,0 +1,49 @@
import ContentWarp from '@/components/ContentWarp';
import styles from '../../index.less';
import { Form, Input, message } from 'antd';
import ButtonComp from '@/components/ButtonComp';
import { setParameter } from '@/services/gql';
import { validateIPAddress } from '@/utils/validate';
export default function Page() {
const [form] = Form.useForm();
const onFinish = (values: any) => {
setParameter({
ipAddress: values.ipAddress
}).then((res) => {
if (res.result == 'success') {
message.success('连接成功')
}else {
message.success(res.errorMsg)
}
})
};
return (
<div className={styles.params_warp}>
<ContentWarp text={'参数设置'}>
<div className='pd20'></div>
<div className='line'></div>
<div className='pd20 pb100'>
<Form form={form} onFinish={onFinish}>
<Form.Item
name="ipAddress"
label="本地GLQ后端IP"
rules={[
{ required: true, message: '请输入本地GLQ后端IP' },
{ validator: validateIPAddress },
]}
>
<Input placeholder="请输入本地GLQ后端IP" style={{ width: '560px' }} />
</Form.Item>
</Form>
<div className={styles.btn_warp}>
<ButtonComp style={{ marginRight: 20 }} text={'建立连接'} onClick={() => form.submit()} />
<ButtonComp type={'cancel'} text={'参数重置'} onClick={() => form.resetFields()} />
</div>
</div>
</ContentWarp>
</div>
);
}

@ -0,0 +1,10 @@
import styles from './index.less';
// GLQ远程维护 --> 交互维护命令--> PING命令
export default function Page() {
return (
<div>
{'GLQ远程维护 --> 交互维护命令--> PING命令'}
</div>
);
}

@ -0,0 +1,10 @@
import styles from './index.less';
// GLQ远程维护 --> 交互维护命令--> 系统时间
export default function Page() {
return (
<div>
{'GLQ远程维护 --> 交互维护命令--> 系统时间'}
</div>
);
}

@ -0,0 +1,10 @@
import styles from './index.less';
// GLQ远程维护 --> 交互维护命令-->TELNET命令
export default function Page() {
return (
<div>
{'GLQ远程维护 --> 交互维护命令-->TELNET命令'}
</div>
);
}

@ -0,0 +1,83 @@
import ContentWarp from '@/components/ContentWarp';
import styles from '../../index.less';
import ButtonComp from '@/components/ButtonComp';
import { useEffect, useRef, useState } from 'react';
import { getGlqInfo } from '@/services/gql';
import ClearInfoDialog from '@/components/ClearInfoDialog';
import SaveAs from '@/components/SaveAs';
// 网络GQL管理 --> 获取防火墙策略
export default function Page() {
const [lines, setLines] = useState<any>([]);
const [currentLineIndex, setCurrentLineIndex] = useState(0);
const [visibility, setVisibility] = useState<boolean>(false);
const outputRef: any = useRef(null);
useEffect(() => {
const timer = setInterval(() => {
if (currentLineIndex < lines.length) {
setCurrentLineIndex((prevIndex) => prevIndex + 1);
} else {
clearInterval(timer);
}
}, 300);
if (outputRef.current.scrollHeight > 330) {
outputRef.current.scrollTop = outputRef.current.scrollHeight;
}
return () => {
clearInterval(timer); // 组件卸载时清除定时器
};
}, [currentLineIndex, lines.length]);
const statusQuery = () => {
getGlqInfo({type: 4}).then((res) => {
if (res?.result == "success") {
setLines([
...lines,
'发送命令成功',
`获取防火墙策略`,
`正在获取防火墙策略中...`,
`获取防火墙策略完成`
])
} else {
setLines([`${res?.errorMsg}`])
}
})
}
return (
<div className={styles.params_warp}>
<ContentWarp text={'获取防火墙策略'}>
<div className='pd20'></div>
<div className='line'></div>
<div className='pd20 pb100'>
<div ref={outputRef} className={styles.html_con}>
<div id='messageInfo' style={{ padding: '0px 12px' }} key={currentLineIndex}>
{lines.slice(0, currentLineIndex).map((line: string, index: number) => (
<p key={index} style={{ paddingTop: index == 0 ? 20 : 10 }}>{line}</p>
))}
</div>
</div>
<div className={styles.btn_warp}>
<ButtonComp style={{ marginRight: 20 }} text={'发送命令'} onClick={() => { statusQuery() }} />
<SaveAs style={{ marginRight: 20}} fileName='获取防火墙策略' domId='messageInfo'/>
<ButtonComp type={'cancel'} disabled={lines.length == 0} text={'清空信息'} onClick={() => setVisibility(true)} />
</div>
</div>
</ContentWarp>
<ClearInfoDialog
visibility={visibility}
onCancel={() => setVisibility(false)}
onOk={() => {
setLines([]);
setCurrentLineIndex(0);
setVisibility(false);
}}>
<div></div>
</ClearInfoDialog>
</div>
);
}

@ -0,0 +1,83 @@
import ContentWarp from '@/components/ContentWarp';
import styles from '../../index.less';
import ButtonComp from '@/components/ButtonComp';
import { useEffect, useRef, useState } from 'react';
import { getGlqInfo } from '@/services/gql';
import ClearInfoDialog from '@/components/ClearInfoDialog';
import SaveAs from '@/components/SaveAs';
// 网络GQL管理 --> 获取日志信息
export default function Page() {
const [lines, setLines] = useState<any>([]);
const [currentLineIndex, setCurrentLineIndex] = useState(0);
const [visibility, setVisibility] = useState<boolean>(false);
const outputRef: any = useRef(null);
useEffect(() => {
const timer = setInterval(() => {
if (currentLineIndex < lines.length) {
setCurrentLineIndex((prevIndex) => prevIndex + 1);
} else {
clearInterval(timer);
}
}, 300);
if (outputRef.current.scrollHeight > 330) {
outputRef.current.scrollTop = outputRef.current.scrollHeight;
}
return () => {
clearInterval(timer); // 组件卸载时清除定时器
};
}, [currentLineIndex, lines.length]);
const statusQuery = () => {
getGlqInfo({type: 4}).then((res) => {
if (res?.result == "success") {
setLines([
...lines,
'发送命令成功',
`获取日志信息`,
`正在获取日志信息中...`,
`获取日志信息完成`
])
} else {
setLines([`${res?.errorMsg}`])
}
})
}
return (
<div className={styles.params_warp}>
<ContentWarp text={'获取日志信息'}>
<div className='pd20'></div>
<div className='line'></div>
<div className='pd20 pb100'>
<div ref={outputRef} className={styles.html_con}>
<div id='messageInfo' style={{ padding: '0px 12px' }} key={currentLineIndex}>
{lines.slice(0, currentLineIndex).map((line: string, index: number) => (
<p key={index} style={{ paddingTop: index == 0 ? 20 : 10 }}>{line}</p>
))}
</div>
</div>
<div className={styles.btn_warp}>
<ButtonComp style={{ marginRight: 20 }} text={'发送命令'} onClick={() => { statusQuery() }} />
<SaveAs style={{ marginRight: 20}} fileName='获取日志信息' domId='messageInfo'/>
<ButtonComp type={'cancel'} disabled={lines.length == 0} text={'清空信息'} onClick={() => setVisibility(true)} />
</div>
</div>
</ContentWarp>
<ClearInfoDialog
visibility={visibility}
onCancel={() => setVisibility(false)}
onOk={() => {
setLines([]);
setCurrentLineIndex(0);
setVisibility(false);
}}>
<div></div>
</ClearInfoDialog>
</div>
);
}

@ -0,0 +1,123 @@
import ContentWarp from '@/components/ContentWarp';
import styles from '../../index.less';
import { Form, Input, Select, message } from 'antd';
import ButtonComp from '@/components/ButtonComp';
import { useEffect } from 'react';
import { remoteFileConfiSendData, remoteFileConfigClean } from '@/services/gql';
// 网络GLQ配置 --> 远程文件配置--> 管理配置
export default function Page() {
const [form] = Form.useForm();
useEffect(() => {
form.setFieldsValue({
deviceLocation: '前端机平台',
deviceType: '类型1',
hotStandby: 'no',
deviceId: '',
})
}, [])
const onFinish = (values: any) => {
remoteFileConfiSendData({
jsonStr: JSON.stringify(values),
type: 4
}).then((res) => {
if (res?.result == "success") {
message.success('文件提交成功');
form.resetFields();
} else {
message.error(res?.errorMsg);
}
})
};
const clearInfo = () => {
remoteFileConfigClean({type: 4}).then(res => {
if (res?.result == "success") {
message.success('清除信息成功');
}else {
message.error(res?.errorMsg);
}
})
}
return (
<div className={`${styles.params_warp}`}>
<ContentWarp text={'管理文件配置'}>
<div className='pd20'></div>
<div className='line'></div>
<div className='pd20 pb100'>
<Form
form={form}
onFinish={onFinish}
>
<Form.Item
name="deviceLocation"
label="设备位置"
rules={[
{ required: true, message: '请选择设备位置' },
]}
>
<Select
style={{ width: 560 }}
onChange={(e) => { }}
options={[
{ label: '前端机平台', value: '前端机平台' },
{ label: '后端机平台', value: '后端机平台' }
]}
/>
</Form.Item>
<Form.Item
name="deviceType"
label="设备类型"
rules={[
{ required: true, message: '请选择设备类型' },
]}
>
<Select
style={{ width: 560 }}
onChange={(e) => { }}
options={[
{ label: '类型1', value: '类型1' },
{ label: '类型2', value: '类型2' }
]}
/>
</Form.Item>
<Form.Item
name="hotStandby"
label="存在热备"
rules={[
{ required: true, message: '请选择存在热备' },
]}
>
<Select
style={{ width: 560 }}
onChange={(e) => { }}
options={[
{ label: 'no', value: 'no' },
{ label: 'yes', value: 'yes' }
]}
/>
</Form.Item>
<Form.Item
name="deviceId"
label="设备标识"
rules={[
{ required: true, message: '请输入设备标识' },
]}
>
<Input placeholder="请输入设备标识" style={{ width: '560px' }} />
</Form.Item>
</Form>
<div className={styles.btn_warp}>
<ButtonComp style={{ marginRight: 20 }} text={'文件提交'} onClick={() => form.submit()} />
<ButtonComp type={'cancel'} text={'清空信息'} onClick={() => clearInfo()} />
</div>
</div>
</ContentWarp>
</div>
);
}

@ -0,0 +1,83 @@
import ContentWarp from '@/components/ContentWarp';
import styles from '../../index.less';
import ButtonComp from '@/components/ButtonComp';
import { useEffect, useRef, useState } from 'react';
import { getGlqInfo } from '@/services/gql';
import ClearInfoDialog from '@/components/ClearInfoDialog';
import SaveAs from '@/components/SaveAs';
// 网络GQL管理 --> 获取管理配置
export default function Page() {
const [lines, setLines] = useState<any>([]);
const [currentLineIndex, setCurrentLineIndex] = useState(0);
const [visibility, setVisibility] = useState<boolean>(false);
const outputRef: any = useRef(null);
useEffect(() => {
const timer = setInterval(() => {
if (currentLineIndex < lines.length) {
setCurrentLineIndex((prevIndex) => prevIndex + 1);
} else {
clearInterval(timer);
}
}, 300);
if (outputRef.current.scrollHeight > 330) {
outputRef.current.scrollTop = outputRef.current.scrollHeight;
}
return () => {
clearInterval(timer); // 组件卸载时清除定时器
};
}, [currentLineIndex, lines.length]);
const statusQuery = () => {
getGlqInfo({type: 4}).then((res) => {
if (res?.result == "success") {
setLines([
...lines,
'发送命令成功',
`获取管理配置`,
`正在获取管理配置中...`,
`获取管理配置完成`
])
} else {
setLines([`${res?.errorMsg}`])
}
})
}
return (
<div className={styles.params_warp}>
<ContentWarp text={'获取管理配置'}>
<div className='pd20'></div>
<div className='line'></div>
<div className='pd20 pb100'>
<div ref={outputRef} className={styles.html_con}>
<div id='messageInfo' style={{ padding: '0px 12px' }} key={currentLineIndex}>
{lines.slice(0, currentLineIndex).map((line: string, index: number) => (
<p key={index} style={{ paddingTop: index == 0 ? 20 : 10 }}>{line}</p>
))}
</div>
</div>
<div className={styles.btn_warp}>
<ButtonComp style={{ marginRight: 20 }} text={'发送命令'} onClick={() => { statusQuery() }} />
<SaveAs style={{ marginRight: 20}} fileName='获取管理配置' domId='messageInfo'/>
<ButtonComp type={'cancel'} disabled={lines.length == 0} text={'清空信息'} onClick={() => setVisibility(true)} />
</div>
</div>
</ContentWarp>
<ClearInfoDialog
visibility={visibility}
onCancel={() => setVisibility(false)}
onOk={() => {
setLines([]);
setCurrentLineIndex(0);
setVisibility(false);
}}>
<div></div>
</ClearInfoDialog>
</div>
);
}

@ -0,0 +1,83 @@
import ContentWarp from '@/components/ContentWarp';
import styles from '../../index.less';
import ButtonComp from '@/components/ButtonComp';
import { useEffect, useRef, useState } from 'react';
import { getGlqInfo } from '@/services/gql';
import ClearInfoDialog from '@/components/ClearInfoDialog';
import SaveAs from '@/components/SaveAs';
// 网络GQL管理 --> 获取网络配置
export default function Page() {
const [lines, setLines] = useState<any>([]);
const [currentLineIndex, setCurrentLineIndex] = useState(0);
const [visibility, setVisibility] = useState<boolean>(false);
const outputRef: any = useRef(null);
useEffect(() => {
const timer = setInterval(() => {
if (currentLineIndex < lines.length) {
setCurrentLineIndex((prevIndex) => prevIndex + 1);
} else {
clearInterval(timer);
}
}, 300);
if (outputRef.current.scrollHeight > 330) {
outputRef.current.scrollTop = outputRef.current.scrollHeight;
}
return () => {
clearInterval(timer); // 组件卸载时清除定时器
};
}, [currentLineIndex, lines.length]);
const statusQuery = () => {
getGlqInfo({type: 2}).then((res) => {
if (res?.result == "success") {
setLines([
...lines,
'发送命令成功',
`获取网络配置`,
`正在获取网络配置中...`,
`获取网络配置完成`
])
} else {
setLines([`${res?.errorMsg}`])
}
})
}
return (
<div className={styles.params_warp}>
<ContentWarp text={'获取网络配置'}>
<div className='pd20'></div>
<div className='line'></div>
<div className='pd20 pb100'>
<div ref={outputRef} className={styles.html_con}>
<div id='messageInfo' style={{ padding: '0px 12px' }} key={currentLineIndex}>
{lines.slice(0, currentLineIndex).map((line: string, index: number) => (
<p key={index} style={{ paddingTop: index == 0 ? 20 : 10 }}>{line}</p>
))}
</div>
</div>
<div className={styles.btn_warp}>
<ButtonComp style={{ marginRight: 20 }} text={'发送命令'} onClick={() => { statusQuery() }} />
<SaveAs style={{ marginRight: 20}} fileName='被控端网络状态信息配置情况' domId='messageInfo'/>
<ButtonComp type={'cancel'} disabled={lines.length == 0} text={'清空信息'} onClick={() => setVisibility(true)} />
</div>
</div>
</ContentWarp>
<ClearInfoDialog
visibility={visibility}
onCancel={() => setVisibility(false)}
onOk={() => {
setLines([]);
setCurrentLineIndex(0);
setVisibility(false);
}}>
<div></div>
</ClearInfoDialog>
</div>
);
}

@ -0,0 +1,6 @@
.params_warp1 {
[class~='ant-form-item-label'] {
width: 80px;
justify-content: flex-end;
}
}

@ -0,0 +1,85 @@
import ContentWarp from '@/components/ContentWarp';
import styles from '../../index.less';
import styles1 from './index.less';
import { Form, Input, message } from 'antd';
import ButtonComp from '@/components/ButtonComp';
import { remoteFileConfiSendData, remoteFileConfigClean } from '@/services/gql';
import { subnetMaskValidator, validateIPAddress } from '@/utils/validate';
// 网络GLQ配置 --> 远程文件配置--> 网络参数
export default function Page() {
const [form] = Form.useForm();
const onFinish = (values: any) => {
remoteFileConfiSendData({
jsonStr: JSON.stringify(values),
type: 2
}).then( (res) => {
if (res?.result == "success") {
message.success('文件提交成功');
form.resetFields();
}else {
message.error(res?.errorMsg);
}
})
};
const clearInfo = () => {
remoteFileConfigClean({type: 2}).then(res => {
if (res?.result == "success") {
message.success('清除信息成功');
}else {
message.error(res?.errorMsg);
}
})
}
return (
<div className={`${styles.params_warp} ${styles1.params_warp1}`}>
<ContentWarp text={'网络参数配置'}>
<div className='pd20'></div>
<div className='line'></div>
<div className='pd20 pb100'>
<Form
form={form}
onFinish={onFinish}
>
<Form.Item
name="ipAddress"
label="IP地址"
rules={[
{ required: true, message: '请输入IP地址' },
{ validator: validateIPAddress }
]}
>
<Input placeholder="请输入IP地址" style={{ width: '560px' }} />
</Form.Item>
<Form.Item
name="mask"
label="子网掩码"
rules={[
{ required: true, message: '请输入子网掩码' }
]}
>
<Input placeholder="请输入子网掩码" style={{ width: '560px' }} />
</Form.Item>
<Form.Item
name="defaultGateway"
label="默认网关"
rules={[
{ required: true, message: '请输入默认网关' },
]}
>
<Input placeholder="请输入默认网关" style={{ width: '560px' }} />
</Form.Item>
</Form>
<div className={styles.btn_warp}>
<ButtonComp style={{ marginRight: 20 }} text={'文件提交'} onClick={() => form.submit()} />
<ButtonComp type={'cancel'} text={'清空信息'} onClick={() => clearInfo()} />
</div>
</div>
</ContentWarp>
</div>
);
}

@ -0,0 +1,101 @@
import ContentWarp from '@/components/ContentWarp';
import styles from '../../index.less';
import { ConfigProvider, Form, Input, Table, message } from 'antd';
import ButtonComp from '@/components/ButtonComp';
import { useEffect, useState } from 'react';
import { rowClassName } from '@/utils';
import { getTextSecretInfo, remoteFileConfiSendData } from '@/services/gql';
import { validateIPAddress } from '@/utils/validate';
// 网络GLQ配置 --> 远程文件配置--> 安全策略
export default function Page() {
const [form] = Form.useForm();
const [tableData, setTableData] = useState([]);
useEffect(() => {
form.setFieldsValue({ip: '114.114.114.114'})
}, [])
const columns: any = [
{
title: '序号', key: 'index', align: 'center', width: 80,
render: (a: any, b: any, c: any) => {
return <span>{c + 1}</span>;
},
},
{ title: '单位名称', dataIndex: '单位名称', key: '单位名称', align: 'center' },
{ title: '设备名称', dataIndex: '设备名称', key: '设备名称', align: 'center' },
{ title: '设备IP', dataIndex: '设备ip', key: '设备ip', align: 'center' },
{ title: '电话号码', dataIndex: '电话号码', key: '电话号码', align: 'center' },
{ title: '设备属性', dataIndex: '设备属性', key: '设备属性', align: 'center' },
{ title: '设备型号', dataIndex: '设备型号', key: '设备型号', align: 'center' },
]
const onFinish = (values: any) => {
getTextSecretInfo(values).then(res => {
if (res?.result == "success") {
setTableData(res?.data[0].jsonStr)
message.success('获取成功');
} else {
message.error(res?.errorMsg);
}
})
};
const sending = () => {
if (tableData.length == 0) {
message.info('请获取普密信息后再发送数据');
return
}
remoteFileConfiSendData({
jsonStr: JSON.stringify(tableData),
type: 3
}).then( (res) => {
if (res?.result == "success") {
message.success('发送数据成功');
}else {
message.error(res?.errorMsg);
}
})
}
return (
<div className={styles.params_warp}>
<ContentWarp text={'安全策略配置'}>
<div className='pd20'></div>
<div className='line'></div>
<div className='pd20 pb100'>
<Table
scroll={tableData.length > 0 ? { y: 41 * 5 } : {}}
pagination={false}
bordered
columns={columns}
dataSource={tableData}
rowKey={(record: any) => record?.id}
rowClassName={rowClassName}
/>
<Form form={form} layout={'inline'} onFinish={onFinish} className='mt20'>
<Form.Item name="ip" label="普密对外服务器IP仅Ⅱ型隔离器时需配置此项" rules={[
{ required: true, message: '请输入普密对外服务器IP' },
{ validator: validateIPAddress }
]} >
<Input placeholder="请输入普密对外服务器IP" style={{ width: '280px' }} />
</Form.Item>
<ButtonComp style={{ marginRight: 20 }} text={'获取普密信息'} onClick={() => form.submit()} />
</Form>
<div className='mt20'></div>
<div className={styles.btn_warp}>
<ButtonComp text={'发送数据'} onClick={() => sending()} />
</div>
</div>
</ContentWarp>
</div>
);
}

@ -0,0 +1,83 @@
import ContentWarp from '@/components/ContentWarp';
import styles from '../../index.less';
import ButtonComp from '@/components/ButtonComp';
import { useEffect, useRef, useState } from 'react';
import { getGlqInfo } from '@/services/gql';
import ClearInfoDialog from '@/components/ClearInfoDialog';
import SaveAs from '@/components/SaveAs';
// 网络GQL管理 --> 获取安全策略
export default function Page() {
const [lines, setLines] = useState<any>([]);
const [currentLineIndex, setCurrentLineIndex] = useState(0);
const [visibility, setVisibility] = useState<boolean>(false);
const outputRef: any = useRef(null);
useEffect(() => {
const timer = setInterval(() => {
if (currentLineIndex < lines.length) {
setCurrentLineIndex((prevIndex) => prevIndex + 1);
} else {
clearInterval(timer);
}
}, 300);
if (outputRef.current.scrollHeight > 330) {
outputRef.current.scrollTop = outputRef.current.scrollHeight;
}
return () => {
clearInterval(timer); // 组件卸载时清除定时器
};
}, [currentLineIndex, lines.length]);
const statusQuery = () => {
getGlqInfo({type: 3}).then((res) => {
if (res?.result == "success") {
setLines([
...lines,
'发送命令成功',
`获取安全策略`,
`正在获取安全策略中...`,
`获取安全策略完成`
])
} else {
setLines([`${res?.errorMsg}`])
}
})
}
return (
<div className={styles.params_warp}>
<ContentWarp text={'获取安全策略'}>
<div className='pd20'></div>
<div className='line'></div>
<div className='pd20 pb100'>
<div ref={outputRef} className={styles.html_con}>
<div id='messageInfo' style={{ padding: '0px 12px' }} key={currentLineIndex}>
{lines.slice(0, currentLineIndex).map((line: string, index: number) => (
<p key={index} style={{ paddingTop: index == 0 ? 20 : 10 }}>{line}</p>
))}
</div>
</div>
<div className={styles.btn_warp}>
<ButtonComp style={{ marginRight: 20 }} text={'发送命令'} onClick={() => { statusQuery() }} />
<SaveAs style={{ marginRight: 20}} fileName='获取安全策略' domId='messageInfo'/>
<ButtonComp type={'cancel'} disabled={lines.length == 0} text={'清空信息'} onClick={() => setVisibility(true)} />
</div>
</div>
</ContentWarp>
<ClearInfoDialog
visibility={visibility}
onCancel={() => setVisibility(false)}
onOk={() => {
setLines([]);
setCurrentLineIndex(0);
setVisibility(false);
}}>
<div></div>
</ClearInfoDialog>
</div>
);
}

@ -0,0 +1,111 @@
import ContentWarp from '@/components/ContentWarp';
import styles from '../../index.less';
import { ConfigProvider, Form, Input, Table, message } from 'antd';
import ButtonComp from '@/components/ButtonComp';
import { useState } from 'react';
import { rowClassName } from '@/utils';
import { validateIPAddress, validatePort } from '@/utils/validate';
import { remoteFileConfiSendData, remoteFileConfigClean } from '@/services/gql';
// 网络GLQ配置 --> 远程文件配置--> 服务列表
export default function Page() {
const [form] = Form.useForm();
const [tableData, setTableData] = useState<any>([]);
const onFinish = (values: any) => {
values.rowKey = Math.random();
setTableData([...tableData, values])
};
const columns: any = [
{
title: '序号', key: 'index', align: 'center', width: 80,
render: (a: any, b: any, c: any) => {
return <span>{c + 1}</span>;
},
},
{ title: '服务名称', dataIndex: 'serviceName', key: 'serviceName', align: 'center' },
{ title: '服务器IP', dataIndex: 'serviceIP', key: 'serviceIP', align: 'center' },
{ title: '服务端口', dataIndex: 'servicePort', key: 'servicePort', align: 'center' },
]
const sending = () => {
if(tableData.length == 0) {
message.info('请添加数据');
return
}
let serviceList = tableData.map(({serviceName, serviceIP, servicePort}: any) => {
return {serviceName, serviceIP, servicePort}
})
remoteFileConfiSendData({
jsonStr: JSON.stringify({ serviceList: serviceList }),
type: 1
}).then( (res) => {
if (res?.result == "success") {
message.success('发送数据成功');
form.resetFields();
}else {
message.error(res?.errorMsg);
}
})
}
const clearInfo = () => {
remoteFileConfigClean({type: 1}).then(res => {
if (res?.result == "success") {
message.success('清除信息成功');
}else {
message.error(res?.errorMsg);
}
})
}
return (
<div className={styles.params_warp}>
<ContentWarp text={'服务列表配置'}>
<div className='pd20'></div>
<div className='line'></div>
<div className='pd20 pb100'>
<Form form={form} layout={'inline'} onFinish={onFinish} className='mb20'>
<Form.Item name="serviceName" label="服务名称" rules={[{ required: true, message: '请输入服务名称' }]} >
<Input placeholder="请输入服务名称" style={{ width: '200px' }} />
</Form.Item>
<Form.Item name="serviceIP" label="服务IP" rules={[
{ required: true, message: '请输入服务IP' },
{ validator: validateIPAddress}
]} >
<Input placeholder="请输入服务IP" style={{ width: '200px' }} />
</Form.Item>
<Form.Item name="servicePort" label="服务端口" rules={[
{ required: true, message: '请输入服务端口' },
{ validator: validatePort }
]} >
<Input placeholder="请输入服务端口" style={{ width: '200px' }} />
</Form.Item>
<ButtonComp text={'提交'} onClick={() => form.submit()} />
</Form>
<Table
scroll={tableData.length > 0 ? { y: 41 * 5 } : {}}
pagination={false}
bordered
columns={columns}
dataSource={tableData}
rowKey={(record: any) => record?.rowKey}
rowClassName={rowClassName}
/>
<div className={styles.btn_warp}>
<ButtonComp style={{ marginRight: 20 }} text={'发送数据'} onClick={() => sending()} />
<ButtonComp type={'cancel'} text={'清空信息'} onClick={() => clearInfo()} />
</div>
</div>
</ContentWarp>
</div>
);
}

@ -0,0 +1,83 @@
import ContentWarp from '@/components/ContentWarp';
import styles from '../../index.less';
import ButtonComp from '@/components/ButtonComp';
import { useEffect, useRef, useState } from 'react';
import { getGlqInfo } from '@/services/gql';
import ClearInfoDialog from '@/components/ClearInfoDialog';
import SaveAs from '@/components/SaveAs';
// 网络GQL管理 --> 获取服务列表
export default function Page() {
const [lines, setLines] = useState<any>([]);
const [currentLineIndex, setCurrentLineIndex] = useState(0);
const [visibility, setVisibility] = useState<boolean>(false);
const outputRef: any = useRef(null);
useEffect(() => {
const timer = setInterval(() => {
if (currentLineIndex < lines.length) {
setCurrentLineIndex((prevIndex) => prevIndex + 1);
} else {
clearInterval(timer);
}
}, 300);
if (outputRef.current.scrollHeight > 330) {
outputRef.current.scrollTop = outputRef.current.scrollHeight;
}
return () => {
clearInterval(timer); // 组件卸载时清除定时器
};
}, [currentLineIndex, lines.length]);
const statusQuery = () => {
getGlqInfo({type: 1}).then((res) => {
if (res?.result == "success") {
setLines([
...lines,
'发送命令成功',
`获取服务列表`,
`正在获取服务列表中...`,
`获取服务列表完成`
])
} else {
setLines([`${res?.errorMsg}`])
}
})
}
return (
<div className={styles.params_warp}>
<ContentWarp text={'获取服务列表'}>
<div className='pd20'></div>
<div className='line'></div>
<div className='pd20 pb100'>
<div ref={outputRef} className={styles.html_con}>
<div id='messageInfo' style={{ padding: '0px 12px' }} key={currentLineIndex}>
{lines.slice(0, currentLineIndex).map((line: string, index: number) => (
<p key={index} style={{ paddingTop: index == 0 ? 20 : 10 }}>{line}</p>
))}
</div>
</div>
<div className={styles.btn_warp}>
<ButtonComp style={{ marginRight: 20 }} text={'发送命令'} onClick={() => { statusQuery() }} />
<SaveAs style={{ marginRight: 20}} fileName='获取服务列表' domId='messageInfo'/>
<ButtonComp type={'cancel'} disabled={lines.length == 0} text={'清空信息'} onClick={() => setVisibility(true)} />
</div>
</div>
</ContentWarp>
<ClearInfoDialog
visibility={visibility}
onCancel={() => setVisibility(false)}
onOk={() => {
setLines([]);
setCurrentLineIndex(0);
setVisibility(false);
}}>
<div></div>
</ClearInfoDialog>
</div>
);
}

@ -0,0 +1,6 @@
.params_warp1 {
[class~='ant-form-item-label'] {
width: 110px;
justify-content: flex-end;
}
}

@ -0,0 +1,194 @@
import ContentWarp from '@/components/ContentWarp';
import styles from '../../index.less';
import styles1 from './index.less';
import { Form, Input, Select, Table, message } from 'antd';
import ButtonComp from '@/components/ButtonComp';
import { useEffect, useState } from 'react';
import { rowClassName } from '@/utils';
import { validateIPAddress } from '@/utils/validate';
import { remoteFileConfiSendData, remoteFileConfigClean } from '@/services/gql';
// 网络GLQ配置 --> 远程文件配置--> VPN策略
export default function Page() {
const [form] = Form.useForm();
const [tableData, setTableData] = useState<any>([]);
const [activeList, setActiveList] = useState<any>([]);
useEffect(() => {
form.setFieldsValue({
unitName: '',
deviceName: '',
deviceIp: '',
deviceId: '',
messageComm: '加密通信',
pingComm: '允许互PING',
})
}, [])
const columns: any = [
{
title: '序号', key: 'index', align: 'center', width: 80,
render: (a: any, b: any, c: any) => {
return <span>{c + 1}</span>;
},
},
{ title: '单位名称', dataIndex: 'unitName', key: 'unitName', align: 'center' },
{ title: '设备名称', dataIndex: 'deviceName', key: 'deviceName', align: 'center' },
{ title: '设备IP', dataIndex: 'deviceIp', key: 'deviceIp', align: 'center' },
{ title: '设备ID', dataIndex: 'deviceId', key: 'deviceId', align: 'center' },
{ title: '报文通信策略', dataIndex: 'messageComm', key: 'messageComm', align: 'center' },
{ title: 'PING通信策略', dataIndex: 'pingComm', key: 'pingComm', align: 'center' },
]
const onFinish = (values: any) => {
values.rowKey = Math.floor(Math.random() * 10000);
setTableData([...tableData, values])
};
const sending = () => {
if (tableData.length == 0) {
message.info('请添加数据');
return
}else if (activeList.length == 0) {
message.info('请勾选需要发送的数据');
return
}
let serviceList = activeList.map(({ unitName, deviceName, deviceIp, deviceId, messageComm, pingComm }: any) => {
return { unitName, deviceName, deviceIp, deviceId, messageComm, pingComm }
})
remoteFileConfiSendData({
jsonStr: JSON.stringify({ serviceList: serviceList }),
type: 5
}).then((res) => {
if (res?.result == "success") {
message.success('发送数据成功');
form.resetFields();
} else {
message.error(res?.errorMsg);
}
})
}
const clearInfo = () => {
remoteFileConfigClean({ type: 5 }).then(res => {
if (res?.result == "success") {
message.success('清除信息成功');
} else {
message.error(res?.errorMsg);
}
})
}
return (
<div className={`${styles.params_warp} ${styles1.params_warp1}`}>
<ContentWarp text={'VPN策略配置'}>
<div className='pd20'>VPN</div>
<div className='line'></div>
<div className='pd20 pb100'>
<Form
form={form}
onFinish={onFinish}
>
<Form.Item
name="unitName"
label="单位名称"
rules={[
{ required: true, message: '请输入单位名称' },
]}
>
<Input placeholder="请输入单位名称" style={{ width: '630px' }} />
</Form.Item>
<Form.Item
name="deviceName"
label="设备名称"
rules={[
{ required: true, message: '请输入设备名称' },
]}
>
<Input placeholder="请输入设备名称" style={{ width: '630px' }} />
</Form.Item>
<div style={{ display: 'flex' }}>
<Form.Item
name="deviceIp"
label="设备IP"
rules={[
{ required: true, message: '请输入设备IP' },
{ validator: validateIPAddress }
]}
>
<Input placeholder="请输入设备IP" style={{ width: '250px', marginRight: 20 }} />
</Form.Item>
<Form.Item
name="deviceId"
label="设备ID"
rules={[
{ required: true, message: '请输入设备ID' },
]}
>
<Input placeholder="请输入设备ID" style={{ width: '250px' }} />
</Form.Item>
</div>
<div style={{ display: 'flex' }}>
<Form.Item
name="messageComm"
label="报文通信策略"
rules={[
{ required: true, message: '请选择报文通信策略' },
]}
>
<Select
style={{ width: 250, marginRight: 20 }}
onChange={(e) => { }}
options={[
{ label: '加密通信', value: '加密通信' },
{ label: '数据明传', value: '数据明传' },
{ label: '通信阻断', value: '通信阻断' }
]}
/>
</Form.Item>
<Form.Item
name="pingComm"
label="PING通信策略"
rules={[
{ required: true, message: '请选择PING通信策略' },
]}
>
<Select
style={{ width: 250, marginRight: 20 }}
onChange={(e) => { }}
options={[
{ label: '允许互PING', value: '允许互PING' },
{ label: '阻断互PING', value: '阻断互PING' }
]}
/>
</Form.Item>
<ButtonComp text={'提交'} onClick={() => form.submit()} />
</div>
</Form>
<Table
scroll={tableData.length > 0 ? { y: 41 * 5 } : {}}
pagination={false}
bordered
columns={columns}
dataSource={tableData}
rowKey={(record: any) => record?.rowKey}
rowClassName={rowClassName}
rowSelection={{
onChange: (selectedRowKeys: any, selectedRows: any) => {
setActiveList(selectedRows)
}
}}
/>
<div className={styles.btn_warp}>
<ButtonComp style={{ marginRight: 20 }} text={'发送数据'} onClick={() => sending()} />
<ButtonComp type={'cancel'} text={'信息清空'} onClick={() => clearInfo()} />
</div>
</div>
</ContentWarp>
</div>
);
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save