Compare commits
82 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33558d3f00 | ||
|
|
5061f16fe7 | ||
|
|
22201bbb2d | ||
|
|
aa842e246b | ||
|
|
52528343bf | ||
|
|
b53426550d | ||
|
|
b5d7ce8685 | ||
|
|
19d563af75 | ||
|
|
48c6434e65 | ||
|
|
b1c96bb123 | ||
|
|
c4273c2074 | ||
|
|
2d09be6341 | ||
|
|
457bf02452 | ||
|
|
011c74d8d7 | ||
|
|
06c72a914e | ||
|
|
94b0f46195 | ||
|
|
55216fe6cf | ||
|
|
3eafac4ad3 | ||
|
|
50892af7a8 | ||
|
|
93e455f645 | ||
|
|
34c57803a1 | ||
|
|
708eb6535e | ||
|
|
e66e645866 | ||
|
|
d31bfe02ee | ||
|
|
be5f4be75f | ||
|
|
50bf0c27c0 | ||
|
|
4f47eebb1e | ||
|
|
9286efa59b | ||
|
|
1e2154c2ae | ||
|
|
af10003b25 | ||
|
|
4aca6823d3 | ||
|
|
7376b20352 | ||
|
|
6fcc6eb5e1 | ||
|
|
52e22cd3a9 | ||
|
|
a86e9aa219 | ||
|
|
1b7d5fc85c | ||
|
|
2fb7a74426 | ||
|
|
c5c7c2c3e0 | ||
|
|
7331624b9b | ||
|
|
cc74e9f84d | ||
|
|
b0d3cec1fa | ||
|
|
3a0d47b596 | ||
|
|
1932795955 | ||
|
|
8d8a710a8f | ||
|
|
a0b0f76e23 | ||
|
|
97bf5994c8 | ||
|
|
667d3b61aa | ||
|
|
28334b2acc | ||
|
|
efec69eb28 | ||
|
|
ccfee93a91 | ||
|
|
58f2fee781 | ||
|
|
df8f75e16f | ||
|
|
f0e299b704 | ||
|
|
77fb580aea | ||
|
|
b72ff26e4f | ||
|
|
4bd46f64a4 | ||
|
|
dc0379a581 | ||
|
|
d5f744bffc | ||
|
|
30a8fc2dc8 | ||
|
|
0e38f24f85 | ||
|
|
96e728a1eb | ||
|
|
665946c4c2 | ||
|
|
05d4b0cd3e | ||
|
|
95394a4b5e | ||
|
|
78ebb6a0fc | ||
|
|
221c39995f | ||
|
|
c184357b73 | ||
|
|
995da7162f | ||
|
|
1d457fff46 | ||
|
|
d12b34087e | ||
|
|
bce9a8e923 | ||
|
|
fa38b9502f | ||
|
|
50d3cd72de | ||
|
|
1db9d09a79 | ||
|
|
720d7d3b99 | ||
|
|
e5a6987eae | ||
|
|
080b84ed6f | ||
|
|
64f812cc7f | ||
|
|
a4d7c60118 | ||
|
|
52a24871c3 | ||
|
|
df6bfd0414 | ||
|
|
7099bd7349 |
@@ -15,7 +15,7 @@
|
|||||||
const protocol = window.location.protocol
|
const protocol = window.location.protocol
|
||||||
let wsprotocol = "ws:"
|
let wsprotocol = "ws:"
|
||||||
const hostname = window.location.hostname
|
const hostname = window.location.hostname
|
||||||
let host = `${hostname}:33030`;
|
let host = `${hostname}:33080`;
|
||||||
if (protocol === 'https:') {
|
if (protocol === 'https:') {
|
||||||
host = `${hostname}:33443`;
|
host = `${hostname}:33443`;
|
||||||
wsprotocol = "wss:"
|
wsprotocol = "wss:"
|
||||||
@@ -25,4 +25,4 @@
|
|||||||
sessionStorage.setItem('baseUrl', `${protocol}//${host}`);
|
sessionStorage.setItem('baseUrl', `${protocol}//${host}`);
|
||||||
// websocket Address
|
// websocket Address
|
||||||
sessionStorage.setItem('wsUrl', `${wsprotocol}//${host}`);
|
sessionStorage.setItem('wsUrl', `${wsprotocol}//${host}`);
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
#imsi,msisdn,sess_rules,pcc_rules,hdr_enrich,rfsp,sar,qos_audio,qos_video,online,offline
|
imsi,msisdn,sess_rules,pcc_rules,hdr_enrich,rfsp,sar,qos_audio,qos_video
|
||||||
460996650000580,62357000580,internet|ims_sig,internet|ims_sig,dnn,1,def_sar,qos_audio,qos_video,0,0
|
001012082101039,1234,internet|ims_sig,internet|ims_sig,321321,255,321312,32131,32131
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
460996650000580,1234567890ABCDEF1234567890ABCDEF,0,8000
|
001011100001157,1234567890ABCDEF1234567890ABCDEF,0,8000,11111111111111111111111111111111
|
||||||
460996650000581,1234567890ABCDEF1234567890ABCDEF,0,8000
|
001011100001158,1234567890ABCDEF1234567890ABCDEF,0,8000,11111111111111111111111111111111
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
460996650000580,62357000580,def_ambr,def_nssai,def_arfb,def_sar,0,3,def_snssai,1-000001&content&ims,1,64,24,65,def_eps,1,010200000000,-
|
001011100001157,62357000583,def_ambr,def_nssai,def_arfb,def_sar,0,3,def_snssai,1-000001&internet&ims,1,64,24,65,def_eps,1,010200000000,-
|
||||||
460996650000581,62357000581,def_ambr,def_nssai,def_arfb,def_sar,0,3,def_snssai,1-000001&content&ims,1,64,24,65,def_eps,1,010200000000,-
|
001011100001158,62357000585,def_ambr,def_nssai,def_arfb,def_sar,0,3,def_snssai,1-000001&internet&ims,1,64,24,65,def_eps,1,010200000000,-
|
||||||
|
|||||||
@@ -66,14 +66,14 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
await appStore.fnSysConf();
|
await appStore.fnSysConf();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 需要系统引导跳转
|
// // 需要系统引导跳转
|
||||||
if (appStore.bootloader && to.path !== '/quick-start') {
|
// if (appStore.bootloader && to.path !== '/quick-start') {
|
||||||
next({ name: 'QuickStart' });
|
// next({ name: 'QuickStart' });
|
||||||
}
|
// }
|
||||||
// 不重复引导
|
// // 不重复引导
|
||||||
if (!appStore.bootloader && to.path === '/quick-start') {
|
// if (!appStore.bootloader && to.path === '/quick-start') {
|
||||||
next({ name: 'Index' });
|
// next({ name: 'Index' });
|
||||||
}
|
// }
|
||||||
|
|
||||||
let token = getAccessToken();
|
let token = getAccessToken();
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ type AppStore = {
|
|||||||
/**版本号 */
|
/**版本号 */
|
||||||
version: string;
|
version: string;
|
||||||
/**系统引导使用 */
|
/**系统引导使用 */
|
||||||
bootloader: boolean;
|
// bootloader: boolean;
|
||||||
/**服务版本 */
|
/**服务版本 */
|
||||||
serverVersion: string;
|
serverVersion: string;
|
||||||
// 用户登录认证
|
// 用户登录认证
|
||||||
@@ -59,7 +59,7 @@ const useAppStore = defineStore('app', {
|
|||||||
appVersion: import.meta.env.VITE_APP_VERSION,
|
appVersion: import.meta.env.VITE_APP_VERSION,
|
||||||
|
|
||||||
version: '-',
|
version: '-',
|
||||||
bootloader: false,
|
// bootloader: false,
|
||||||
serverVersion: '-',
|
serverVersion: '-',
|
||||||
loginAuth: true,
|
loginAuth: true,
|
||||||
cryptoApi: true,
|
cryptoApi: true,
|
||||||
@@ -91,12 +91,12 @@ const useAppStore = defineStore('app', {
|
|||||||
if (res.code === RESULT_CODE_SUCCESS && res.data) {
|
if (res.code === RESULT_CODE_SUCCESS && res.data) {
|
||||||
this.version = res.data.version;
|
this.version = res.data.version;
|
||||||
this.serverVersion = res.data.serverVersion;
|
this.serverVersion = res.data.serverVersion;
|
||||||
this.bootloader = res.data.bootloader === 'true';
|
// this.bootloader = res.data.bootloader === 'true';
|
||||||
// 引导时
|
// // 引导时
|
||||||
if (this.bootloader) {
|
// if (this.bootloader) {
|
||||||
delAccessToken();
|
// delAccessToken();
|
||||||
delRefreshToken();
|
// delRefreshToken();
|
||||||
}
|
// }
|
||||||
this.loginAuth = res.data.loginAuth !== 'false';
|
this.loginAuth = res.data.loginAuth !== 'false';
|
||||||
this.cryptoApi = res.data.cryptoApi !== 'false';
|
this.cryptoApi = res.data.cryptoApi !== 'false';
|
||||||
sessionSet(CACHE_SESSION_CRYPTO_API, res.data.cryptoApi);
|
sessionSet(CACHE_SESSION_CRYPTO_API, res.data.cryptoApi);
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ function fnFinish() {
|
|||||||
:rules="[
|
:rules="[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
min: 6,
|
min: 5,
|
||||||
max: 26,
|
max: 26,
|
||||||
message: t('views.account.settings.oldPasswordTip'),
|
message: t('views.account.settings.oldPasswordTip'),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -324,12 +324,6 @@ onBeforeUnmount(() => {
|
|||||||
:loading="tableState.loading"
|
:loading="tableState.loading"
|
||||||
:pagination="false"
|
:pagination="false"
|
||||||
:scroll="{ x: true }"
|
:scroll="{ x: true }"
|
||||||
:row-selection="{
|
|
||||||
type: 'radio',
|
|
||||||
columnWidth: '48px',
|
|
||||||
selectedRowKeys: tableState.selectedRowKeys,
|
|
||||||
onChange: fnTableSelectedRowKeys,
|
|
||||||
}"
|
|
||||||
>
|
>
|
||||||
<template #bodyCell="{ column, record }">
|
<template #bodyCell="{ column, record }">
|
||||||
<template v-if="column.key === 'status'">
|
<template v-if="column.key === 'status'">
|
||||||
@@ -351,6 +345,7 @@ onBeforeUnmount(() => {
|
|||||||
:title="`${t('views.index.mark')} - ${serverState.neName || 'OMC'}`"
|
:title="`${t('views.index.mark')} - ${serverState.neName || 'OMC'}`"
|
||||||
style="margin-top: 16px"
|
style="margin-top: 16px"
|
||||||
size="small"
|
size="small"
|
||||||
|
v-if="false"
|
||||||
>
|
>
|
||||||
<a-descriptions
|
<a-descriptions
|
||||||
bordered
|
bordered
|
||||||
|
|||||||
@@ -679,7 +679,6 @@ onBeforeUnmount(() => {
|
|||||||
.toDeep :deep(.ant-select-selection-item) {
|
.toDeep :deep(.ant-select-selection-item) {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toDeep-text {
|
.toDeep-text {
|
||||||
color: #4c9bfd !important;
|
color: #4c9bfd !important;
|
||||||
font-size: 0.844rem !important;
|
font-size: 0.844rem !important;
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ onMounted(() => {
|
|||||||
:rules="[
|
:rules="[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
min: 6,
|
min: 5,
|
||||||
max: 26,
|
max: 26,
|
||||||
message: t('valid.passwordPlease'),
|
message: t('valid.passwordPlease'),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ function fnFinish() {
|
|||||||
:rules="[
|
:rules="[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
min: 6,
|
min: 5,
|
||||||
max: 26,
|
max: 26,
|
||||||
message: t('valid.passwordPlease'),
|
message: t('valid.passwordPlease'),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ function fnFinish() {
|
|||||||
:rules="[
|
:rules="[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
min: 6,
|
min: 5,
|
||||||
max: 26,
|
max: 26,
|
||||||
message: t('valid.passwordPlease'),
|
message: t('valid.passwordPlease'),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -636,10 +636,10 @@ onMounted(() => {
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<!-- 主机连接配置 -->
|
<!-- 主机连接配置 -->
|
||||||
<a-divider orientation="left">
|
<a-divider orientation="left" v-if="false">
|
||||||
{{ t('views.ne.neInfo.hostConfig') }}
|
{{ t('views.ne.neInfo.hostConfig') }}
|
||||||
</a-divider>
|
</a-divider>
|
||||||
<a-collapse class="collapse" ghost>
|
<a-collapse class="collapse" ghost v-if="false">
|
||||||
<a-collapse-panel
|
<a-collapse-panel
|
||||||
v-for="host in modalState.from.hosts.filter(
|
v-for="host in modalState.from.hosts.filter(
|
||||||
(s:any) => !(s.hostType === 'telnet' && modalState.from.neType === 'OMC')
|
(s:any) => !(s.hostType === 'telnet' && modalState.from.neType === 'OMC')
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ let fromState = ref({
|
|||||||
ue_pool: '10.2.1.0/24',
|
ue_pool: '10.2.1.0/24',
|
||||||
// 非指定属性
|
// 非指定属性
|
||||||
mmes1_ip: '192.168.8.220/20',
|
mmes1_ip: '192.168.8.220/20',
|
||||||
mmes10_ip: '172.16.5.221/24',
|
mmes10_ip: '127.0.0.221/24',
|
||||||
mmes11_ip: '172.16.5.220/24',
|
mmes11_ip: '127.0.0.220/24',
|
||||||
ims_sip_ip: '192.168.8.110',
|
ims_sip_ip: '192.168.8.110',
|
||||||
upf_type: 'LightUPF',
|
upf_type: 'LightUPF',
|
||||||
upf_driver_type: 'vmxnet3',
|
upf_driver_type: 'vmxnet3',
|
||||||
@@ -58,22 +58,22 @@ let fromState = ref({
|
|||||||
upfn6_mac: '00:00:00:00:00:00',
|
upfn6_mac: '00:00:00:00:00:00',
|
||||||
},
|
},
|
||||||
sbi: {
|
sbi: {
|
||||||
omc_ip: '172.16.5.100',
|
omc_ip: '127.0.0.100',
|
||||||
ims_ip: '172.16.5.110',
|
ims_ip: '127.0.0.110',
|
||||||
amf_ip: '172.16.5.120',
|
amf_ip: '127.0.0.120',
|
||||||
ausf_ip: '172.16.5.130',
|
ausf_ip: '127.0.0.130',
|
||||||
udm_ip: '172.16.5.140',
|
udm_ip: '127.0.0.140',
|
||||||
db_ip: '0.0.0.0',
|
db_ip: '127.0.0.1',
|
||||||
smf_ip: '172.16.5.150',
|
smf_ip: '127.0.0.150',
|
||||||
pcf_ip: '172.16.5.160',
|
pcf_ip: '127.0.0.160',
|
||||||
nssf_ip: '172.16.5.170',
|
nssf_ip: '127.0.0.170',
|
||||||
nrf_ip: '172.16.5.180',
|
nrf_ip: '127.0.0.180',
|
||||||
upf_ip: '172.16.5.190',
|
upf_ip: '127.0.0.190',
|
||||||
lmf_ip: '172.16.5.200',
|
lmf_ip: '127.0.0.200',
|
||||||
nef_ip: '172.16.5.210',
|
nef_ip: '127.0.0.210',
|
||||||
mme_ip: '172.16.5.220',
|
mme_ip: '127.0.0.220',
|
||||||
n3iwf_ip: '172.16.5.230',
|
n3iwf_ip: '127.0.0.230',
|
||||||
smsc_ip: '172.16.5.240',
|
smsc_ip: '127.0.0.240',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -920,7 +920,7 @@ onMounted(() => {
|
|||||||
v-perms:has="['neData:udm-auth:export-dec']"
|
v-perms:has="['neData:udm-auth:export-dec']"
|
||||||
>
|
>
|
||||||
<template #icon><ExportOutlined /></template>
|
<template #icon><ExportOutlined /></template>
|
||||||
Export Dec
|
{{ t('views.neUser.auth.export') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
|
|
||||||
<a-button
|
<a-button
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import {
|
|||||||
resetUDMSub,
|
resetUDMSub,
|
||||||
updateUDMSub,
|
updateUDMSub,
|
||||||
} from '@/api/neData/udm_sub';
|
} from '@/api/neData/udm_sub';
|
||||||
|
import { getNeConfigData, addNeConfigData } from '@/api/ne/neConfig';
|
||||||
import { uploadFile } from '@/api/tool/file';
|
import { uploadFile } from '@/api/tool/file';
|
||||||
import { getNeViewFile } from '@/api/tool/neFile';
|
import { getNeViewFile } from '@/api/tool/neFile';
|
||||||
import { parseDateToStr } from '@/utils/date-utils';
|
import { parseDateToStr } from '@/utils/date-utils';
|
||||||
@@ -112,39 +113,42 @@ let tableColumns = ref<ColumnsType>([
|
|||||||
{
|
{
|
||||||
title: 'Subscribed AMBR',
|
title: 'Subscribed AMBR',
|
||||||
dataIndex: 'ambr',
|
dataIndex: 'ambr',
|
||||||
align: 'center',
|
align: 'left',
|
||||||
width: 100,
|
resizable: true,
|
||||||
|
width: 150,
|
||||||
|
minWidth: 150,
|
||||||
|
maxWidth: 300,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Subscribed SNSSAIs',
|
title: 'Subscribed SNSSAIs',
|
||||||
dataIndex: 'nssai',
|
dataIndex: 'nssai',
|
||||||
align: 'center',
|
align: 'left',
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Forbidden Areas',
|
title: 'Forbidden Areas',
|
||||||
dataIndex: 'arfb',
|
dataIndex: 'arfb',
|
||||||
align: 'center',
|
align: 'left',
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Service Area Restrict',
|
title: 'Service Area Restrict',
|
||||||
dataIndex: 'sar',
|
dataIndex: 'sar',
|
||||||
align: 'center',
|
align: 'left',
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '5G',
|
title: '5G',
|
||||||
dataIndex: 'cn',
|
dataIndex: 'cn',
|
||||||
key: 'cnFlag',
|
key: 'cnFlag',
|
||||||
align: 'center',
|
align: 'left',
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '4G',
|
title: '4G',
|
||||||
dataIndex: 'epsFlag',
|
dataIndex: 'epsFlag',
|
||||||
key: 'epsFlag',
|
key: 'epsFlag',
|
||||||
align: 'center',
|
align: 'left',
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -248,6 +252,10 @@ type ModalStateType = {
|
|||||||
confirmLoading: boolean;
|
confirmLoading: boolean;
|
||||||
/**更新加载数据按钮 loading */
|
/**更新加载数据按钮 loading */
|
||||||
loadDataLoading: boolean;
|
loadDataLoading: boolean;
|
||||||
|
/**5G Subscribed UE AMBR 模板对象 */
|
||||||
|
ambr: Record<string, any>;
|
||||||
|
/**已有AMBE数据 */
|
||||||
|
ambrData: Record<string, any>[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**对话框对象信息状态 */
|
/**对话框对象信息状态 */
|
||||||
@@ -299,6 +307,36 @@ let modalState: ModalStateType = reactive({
|
|||||||
},
|
},
|
||||||
confirmLoading: false,
|
confirmLoading: false,
|
||||||
loadDataLoading: false,
|
loadDataLoading: false,
|
||||||
|
// 5G Subscribed UE AMBR
|
||||||
|
ambr: {
|
||||||
|
uplink: 1,
|
||||||
|
uplinkUnit: 'Gbps',
|
||||||
|
downlink: 2,
|
||||||
|
downlinkUnit: 'Gbps',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'bps',
|
||||||
|
value: 'bps',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Kbps',
|
||||||
|
value: 'Kbps',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Mbps',
|
||||||
|
value: 'Mbps',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Gbps',
|
||||||
|
value: 'Gbps',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Tbps',
|
||||||
|
value: 'Tbps',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
ambrData: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
/**表单中多选的OPTION */
|
/**表单中多选的OPTION */
|
||||||
@@ -397,7 +435,23 @@ function fnModalVisibleByBatch() {
|
|||||||
* 对话框弹出显示为 新增或者修改
|
* 对话框弹出显示为 新增或者修改
|
||||||
* @param noticeId 网元id, 不传为新增
|
* @param noticeId 网元id, 不传为新增
|
||||||
*/
|
*/
|
||||||
function fnModalVisibleByEdit(imsi?: string) {
|
async function fnModalVisibleByEdit(imsi?: string) {
|
||||||
|
const neId = queryParams.neId || '-';
|
||||||
|
|
||||||
|
// 获取AMBR数据
|
||||||
|
const ambrRes = await getNeConfigData({
|
||||||
|
neType: 'UDM',
|
||||||
|
neId: neId,
|
||||||
|
paramName: 'subsUEAmbr',
|
||||||
|
});
|
||||||
|
if (ambrRes.code === RESULT_CODE_SUCCESS) {
|
||||||
|
modalState.ambr.uplink = 1;
|
||||||
|
modalState.ambr.uplinkUnit = 'Gbps';
|
||||||
|
modalState.ambr.downlink = 2;
|
||||||
|
modalState.ambr.downlinkUnit = 'Gbps';
|
||||||
|
modalState.ambrData = ambrRes.data;
|
||||||
|
}
|
||||||
|
|
||||||
if (!imsi) {
|
if (!imsi) {
|
||||||
modalStateFrom.resetFields();
|
modalStateFrom.resetFields();
|
||||||
modalState.title = t('common.addText') + t('views.neUser.sub.subInfo');
|
modalState.title = t('common.addText') + t('views.neUser.sub.subInfo');
|
||||||
@@ -406,60 +460,68 @@ function fnModalVisibleByEdit(imsi?: string) {
|
|||||||
if (modalState.confirmLoading) return;
|
if (modalState.confirmLoading) return;
|
||||||
const hide = message.loading(t('common.loading'), 0);
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
modalState.confirmLoading = true;
|
modalState.confirmLoading = true;
|
||||||
const neId = queryParams.neId || '-';
|
// 获取IMSI数据
|
||||||
getUDMSub(neId, imsi)
|
const res = await getUDMSub(neId, imsi);
|
||||||
.then(res => {
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
if (res.code === RESULT_CODE_SUCCESS) {
|
transformFormData(res.data.smData);
|
||||||
transformFormData(res.data.smData);
|
let ardAll = parseInt(res.data.ard).toString(2).padStart(8, '0');
|
||||||
let ardAll = parseInt(res.data.ard).toString(2).padStart(8, '0');
|
let hplAll = parseInt(res.data.hplmnOdb).toString(2).padStart(8, '0');
|
||||||
let hplAll = parseInt(res.data.hplmnOdb).toString(2).padStart(8, '0');
|
let odbAll = parseInt(res.data.epsOdb).toString(2).padStart(9, '0');
|
||||||
let odbAll = parseInt(res.data.epsOdb).toString(2).padStart(9, '0');
|
const ardArray: any[] = [];
|
||||||
const ardArray: any[] = [];
|
const hplmnArray: any[] = [];
|
||||||
const hplmnArray: any[] = [];
|
const epsOdbArray: any[] = [];
|
||||||
const epsOdbArray: any[] = [];
|
for (let i = 0; i < ardAll.length; i++) {
|
||||||
for (let i = 0; i < ardAll.length; i++) {
|
if (PrefixZero(ardAll, ardAll.length).charAt(i) === '1') {
|
||||||
if (PrefixZero(ardAll, ardAll.length).charAt(i) === '1') {
|
ardArray.push(i);
|
||||||
ardArray.push(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < hplAll.length; i++) {
|
|
||||||
if (PrefixZero(hplAll, hplAll.length).charAt(i) === '1') {
|
|
||||||
hplmnArray.push(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (let i = 0; i < odbAll.length; i++) {
|
|
||||||
if (PrefixZero(odbAll, odbAll.length).charAt(i) === '1') {
|
|
||||||
epsOdbArray.push(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res.data.ard = ardArray;
|
|
||||||
res.data.hplmnOdb = hplmnArray;
|
|
||||||
res.data.epsOdb = epsOdbArray;
|
|
||||||
|
|
||||||
// 4G APN Context List
|
|
||||||
const apnContextStr = res.data.apnContext;
|
|
||||||
const apnContextArr = [];
|
|
||||||
for (let i = 0; i < apnContextStr.length; i += 2) {
|
|
||||||
const num = Number(`${apnContextStr[i]}${apnContextStr[i + 1]}`);
|
|
||||||
apnContextArr.push(num);
|
|
||||||
}
|
|
||||||
|
|
||||||
modalState.from = Object.assign(modalState.from, res.data, {
|
|
||||||
apnContext: apnContextArr,
|
|
||||||
});
|
|
||||||
|
|
||||||
modalState.title =
|
|
||||||
t('common.editText') + t('views.neUser.sub.subInfo');
|
|
||||||
modalState.openByEdit = true;
|
|
||||||
} else {
|
|
||||||
message.error(t('common.getInfoFail'), 2);
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.finally(() => {
|
|
||||||
hide();
|
for (let i = 0; i < hplAll.length; i++) {
|
||||||
modalState.confirmLoading = false;
|
if (PrefixZero(hplAll, hplAll.length).charAt(i) === '1') {
|
||||||
|
hplmnArray.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i = 0; i < odbAll.length; i++) {
|
||||||
|
if (PrefixZero(odbAll, odbAll.length).charAt(i) === '1') {
|
||||||
|
epsOdbArray.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.data.ard = ardArray;
|
||||||
|
res.data.hplmnOdb = hplmnArray;
|
||||||
|
res.data.epsOdb = epsOdbArray;
|
||||||
|
|
||||||
|
// 4G APN Context List
|
||||||
|
const apnContextStr = res.data.apnContext;
|
||||||
|
const apnContextArr = [];
|
||||||
|
for (let i = 0; i < apnContextStr.length; i += 2) {
|
||||||
|
const num = Number(`${apnContextStr[i]}${apnContextStr[i + 1]}`);
|
||||||
|
apnContextArr.push(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
modalState.from = Object.assign(modalState.from, res.data, {
|
||||||
|
apnContext: apnContextArr,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// AMBR数据
|
||||||
|
const ambrItem = modalState.ambrData.find(
|
||||||
|
item => item.name === modalState.from.ambr
|
||||||
|
);
|
||||||
|
if (ambrItem) {
|
||||||
|
const uplinkItme = ambrItem.uplink.split(' ');
|
||||||
|
modalState.ambr.uplink = uplinkItme[0] || 1;
|
||||||
|
modalState.ambr.uplinkUnit = uplinkItme[1] || 'Gbps';
|
||||||
|
const downlinkItme = ambrItem.downlink.split(' ');
|
||||||
|
modalState.ambr.downlink = downlinkItme[0] || 2;
|
||||||
|
modalState.ambr.downlinkUnit = downlinkItme[1] || 'Gbps';
|
||||||
|
}
|
||||||
|
|
||||||
|
modalState.title = t('common.editText') + t('views.neUser.sub.subInfo');
|
||||||
|
modalState.openByEdit = true;
|
||||||
|
} else {
|
||||||
|
message.error(t('common.getInfoFail'), 2);
|
||||||
|
}
|
||||||
|
hide();
|
||||||
|
modalState.confirmLoading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -625,7 +687,7 @@ function fnModalOk() {
|
|||||||
|
|
||||||
modalStateFrom
|
modalStateFrom
|
||||||
.validate()
|
.validate()
|
||||||
.then(e => {
|
.then(async e => {
|
||||||
modalState.confirmLoading = true;
|
modalState.confirmLoading = true;
|
||||||
let ardArr = [0, 0, 0, 0, 0, 0, 0, 0];
|
let ardArr = [0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
let hplmnArr = [0, 0, 0, 0, 0, 0, 0, 0];
|
let hplmnArr = [0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
@@ -657,58 +719,107 @@ function fnModalOk() {
|
|||||||
from.regTimer = `${from.regTimer}`;
|
from.regTimer = `${from.regTimer}`;
|
||||||
from.ueUsageType = `${from.ueUsageType}`;
|
from.ueUsageType = `${from.ueUsageType}`;
|
||||||
from.neId = queryParams.neId || '-';
|
from.neId = queryParams.neId || '-';
|
||||||
const result = from.id
|
|
||||||
? updateUDMSub(from)
|
// 组合检查ambr
|
||||||
: from.num === 1
|
from.ambr = await fnAMBRName();
|
||||||
? addUDMSub(from)
|
|
||||||
: batchAddUDMSub(from, from.num);
|
let res = null;
|
||||||
|
if (from.id) {
|
||||||
|
res = await updateUDMSub(from);
|
||||||
|
} else {
|
||||||
|
if (from.num === 1) {
|
||||||
|
res = await addUDMSub(from);
|
||||||
|
} else {
|
||||||
|
res = await batchAddUDMSub(from, from.num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!res) return;
|
||||||
|
|
||||||
const hide = message.loading(t('common.loading'), 0);
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
result
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
.then(res => {
|
if (from.num === 1) {
|
||||||
if (res.code === RESULT_CODE_SUCCESS) {
|
message.success({
|
||||||
if (from.num === 1) {
|
content: t('common.msgSuccess', { msg: modalState.title }),
|
||||||
message.success({
|
duration: 3,
|
||||||
content: t('common.msgSuccess', { msg: modalState.title }),
|
});
|
||||||
duration: 3,
|
fnGetList(1);
|
||||||
});
|
} else {
|
||||||
fnGetList(1);
|
const timerS = Math.ceil(+from.num / 800) + 1;
|
||||||
} else {
|
notification.success({
|
||||||
const timerS = Math.ceil(+from.num / 800) + 1;
|
message: modalState.title,
|
||||||
notification.success({
|
description: t('common.operateOk'),
|
||||||
message: modalState.title,
|
duration: timerS,
|
||||||
description: t('common.operateOk'),
|
});
|
||||||
duration: timerS,
|
setTimeout(() => {
|
||||||
});
|
fnGetList(1);
|
||||||
setTimeout(() => {
|
}, timerS * 1000);
|
||||||
fnGetList(1);
|
}
|
||||||
}, timerS * 1000);
|
} else {
|
||||||
}
|
if (from.num === 1) {
|
||||||
} else {
|
message.error({
|
||||||
if (from.num === 1) {
|
content: `${res.msg}`,
|
||||||
message.error({
|
duration: 3,
|
||||||
content: `${res.msg}`,
|
});
|
||||||
duration: 3,
|
} else {
|
||||||
});
|
notification.error({
|
||||||
} else {
|
message: modalState.title,
|
||||||
notification.error({
|
description: res.msg,
|
||||||
message: modalState.title,
|
duration: 3,
|
||||||
description: res.msg,
|
});
|
||||||
duration: 3,
|
}
|
||||||
});
|
}
|
||||||
}
|
|
||||||
}
|
hide();
|
||||||
})
|
fnModalCancel();
|
||||||
.finally(() => {
|
modalState.confirmLoading = false;
|
||||||
hide();
|
|
||||||
fnModalCancel();
|
|
||||||
modalState.confirmLoading = false;
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
message.error(t('common.errorFields', { num: e.errorFields.length }), 3);
|
message.error(t('common.errorFields', { num: e.errorFields.length }), 3);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查ambr是否存在,不存在则新增
|
||||||
|
*/
|
||||||
|
async function fnAMBRName() {
|
||||||
|
const ambrItem = modalState.ambrData.find(
|
||||||
|
item =>
|
||||||
|
item.downlink ===
|
||||||
|
`${modalState.ambr.downlink} ${modalState.ambr.downlinkUnit}` &&
|
||||||
|
item.uplink === `${modalState.ambr.uplink} ${modalState.ambr.uplinkUnit}`
|
||||||
|
);
|
||||||
|
if (ambrItem) {
|
||||||
|
return ambrItem.name;
|
||||||
|
} else {
|
||||||
|
// 新增
|
||||||
|
const ambrData = modalState.ambrData.sort((a: any, b: any) => {
|
||||||
|
return b.index - a.index;
|
||||||
|
});
|
||||||
|
if (ambrData.length > 0) {
|
||||||
|
const neId = queryParams.neId || '-';
|
||||||
|
const loc = ambrData[0].index + 1;
|
||||||
|
const name = `ambr_${modalState.ambr.uplink}${modalState.ambr.uplinkUnit}_${modalState.ambr.downlink}${modalState.ambr.downlinkUnit}`;
|
||||||
|
const ambrRes = await addNeConfigData({
|
||||||
|
neType: 'UDM',
|
||||||
|
neId: neId,
|
||||||
|
paramName: 'subsUEAmbr',
|
||||||
|
paramData: {
|
||||||
|
index: loc,
|
||||||
|
name: name,
|
||||||
|
uplink: `${modalState.ambr.uplink} ${modalState.ambr.uplinkUnit}`,
|
||||||
|
downlink: `${modalState.ambr.downlink} ${modalState.ambr.downlinkUnit}`,
|
||||||
|
},
|
||||||
|
loc: `${loc}`,
|
||||||
|
});
|
||||||
|
if (ambrRes.code === RESULT_CODE_SUCCESS) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 'def_ambr';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**对话框内批量添加表单属性和校验规则 */
|
/**对话框内批量添加表单属性和校验规则 */
|
||||||
const modalStateBatchDelFrom = Form.useForm(
|
const modalStateBatchDelFrom = Form.useForm(
|
||||||
modalState.BatchDelForm,
|
modalState.BatchDelForm,
|
||||||
@@ -1709,7 +1820,7 @@ onMounted(() => {
|
|||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :lg="24" :md="24" :xs="24">
|
<!-- <a-col :lg="24" :md="24" :xs="24">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="5G Subscribed UE AMBR Template"
|
label="5G Subscribed UE AMBR Template"
|
||||||
name="ambr"
|
name="ambr"
|
||||||
@@ -1732,7 +1843,41 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
</a-col> -->
|
||||||
|
|
||||||
|
<a-col :lg="24" :md="24" :xs="24">
|
||||||
|
<a-form-item label="5G Subscribed UE AMBR" name="ambr">
|
||||||
|
<a-row :gutter="8">
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-input v-model:value="modalState.ambr.uplink">
|
||||||
|
<template #addonBefore>Uplink</template>
|
||||||
|
<template #addonAfter>
|
||||||
|
<a-select
|
||||||
|
v-model:value="modalState.ambr.uplinkUnit"
|
||||||
|
style="width: 100px"
|
||||||
|
:options="modalState.ambr.options"
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
</template>
|
||||||
|
</a-input>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-input v-model:value="modalState.ambr.downlink">
|
||||||
|
<template #addonBefore>Downlink</template>
|
||||||
|
<template #addonAfter>
|
||||||
|
<a-select
|
||||||
|
v-model:value="modalState.ambr.downlinkUnit"
|
||||||
|
style="width: 100px"
|
||||||
|
:options="modalState.ambr.options"
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
</template>
|
||||||
|
</a-input>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
|
||||||
<a-col :lg="24" :md="24" :xs="24">
|
<a-col :lg="24" :md="24" :xs="24">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="5G Subscribed SNSSAIs Template"
|
label="5G Subscribed SNSSAIs Template"
|
||||||
|
|||||||
1129
src/views/perfManage/kpiOverView/index-hasC.vue
Normal file
1129
src/views/perfManage/kpiOverView/index-hasC.vue
Normal file
File diff suppressed because it is too large
Load Diff
1127
src/views/perfManage/kpiOverView/index-orgin.vue
Normal file
1127
src/views/perfManage/kpiOverView/index-orgin.vue
Normal file
File diff suppressed because it is too large
Load Diff
@@ -169,7 +169,7 @@ onMounted(() => {
|
|||||||
:rules="[
|
:rules="[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
min: 6,
|
min: 5,
|
||||||
max: 26,
|
max: 26,
|
||||||
validator: fnEqualToPassword,
|
validator: fnEqualToPassword,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { Modal } from 'ant-design-vue/es';
|
|||||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
import { delAccessToken, delRefreshToken } from '@/plugins/auth-token';
|
import { delAccessToken, delRefreshToken } from '@/plugins/auth-token';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import useAppStore from '@/store/modules/app';
|
|
||||||
import useI18n from '@/hooks/useI18n';
|
import useI18n from '@/hooks/useI18n';
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import { bootloaderDone } from '@/api/system/quick-start/bootloader';
|
import { bootloaderDone } from '@/api/system/quick-start/bootloader';
|
||||||
@@ -56,8 +55,9 @@ function fnGuideDone() {
|
|||||||
bootloaderDone()
|
bootloaderDone()
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.code === RESULT_CODE_SUCCESS) {
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
useAppStore().bootloader = false;
|
// useAppStore().bootloader = false;
|
||||||
delAccessToken();
|
delAccessToken();
|
||||||
|
delRefreshToken();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
|
|||||||
@@ -834,46 +834,6 @@ onMounted(() => {
|
|||||||
>
|
>
|
||||||
<!-- 表格搜索栏 -->
|
<!-- 表格搜索栏 -->
|
||||||
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
||||||
<a-row :gutter="16">
|
|
||||||
<a-col :lg="18" :md="12" :xs="24">
|
|
||||||
<a-form-item
|
|
||||||
:label="t('views.system.user.className')"
|
|
||||||
name="deptId"
|
|
||||||
>
|
|
||||||
<a-tree-select
|
|
||||||
v-model:value="queryParams.deptId"
|
|
||||||
show-search
|
|
||||||
tree-default-expand-all
|
|
||||||
:tree-data="deptTreeData"
|
|
||||||
:field-names="{
|
|
||||||
children: 'children',
|
|
||||||
label: 'label',
|
|
||||||
value: 'id',
|
|
||||||
}"
|
|
||||||
tree-node-label-prop="label"
|
|
||||||
tree-node-filter-prop="label"
|
|
||||||
style="width: 100%"
|
|
||||||
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
|
|
||||||
:placeholder="t('common.selectPlease')"
|
|
||||||
>
|
|
||||||
</a-tree-select>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
<a-col :lg="6" :md="12" :xs="24">
|
|
||||||
<a-form-item>
|
|
||||||
<a-space :size="8">
|
|
||||||
<a-button type="primary" @click.prevent="fnGetList(1)">
|
|
||||||
<template #icon><SearchOutlined /></template>
|
|
||||||
{{ t('common.search') }}
|
|
||||||
</a-button>
|
|
||||||
<a-button type="default" @click.prevent="fnQueryReset">
|
|
||||||
<template #icon><ClearOutlined /></template>
|
|
||||||
{{ t('common.reset') }}
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
<a-col :lg="6" :md="12" :xs="24">
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
@@ -937,11 +897,52 @@ onMounted(() => {
|
|||||||
bordered
|
bordered
|
||||||
:show-time="{ format: 'HH:mm:ss' }"
|
:show-time="{ format: 'HH:mm:ss' }"
|
||||||
format="YYYY-MM-DD HH:mm:ss"
|
format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
value-format="x"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
></a-range-picker>
|
></a-range-picker>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :lg="18" :md="12" :xs="24" v-if="false">
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.system.user.className')"
|
||||||
|
name="deptId"
|
||||||
|
>
|
||||||
|
<a-tree-select
|
||||||
|
v-model:value="queryParams.deptId"
|
||||||
|
show-search
|
||||||
|
tree-default-expand-all
|
||||||
|
:tree-data="deptTreeData"
|
||||||
|
:field-names="{
|
||||||
|
children: 'children',
|
||||||
|
label: 'label',
|
||||||
|
value: 'id',
|
||||||
|
}"
|
||||||
|
tree-node-label-prop="label"
|
||||||
|
tree-node-filter-prop="label"
|
||||||
|
style="width: 100%"
|
||||||
|
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
|
||||||
|
:placeholder="t('common.selectPlease')"
|
||||||
|
>
|
||||||
|
</a-tree-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
|
<a-form-item>
|
||||||
|
<a-space :size="8">
|
||||||
|
<a-button type="primary" @click.prevent="fnGetList(1)">
|
||||||
|
<template #icon><SearchOutlined /></template>
|
||||||
|
{{ t('common.search') }}
|
||||||
|
</a-button>
|
||||||
|
<a-button type="default" @click.prevent="fnQueryReset">
|
||||||
|
<template #icon><ClearOutlined /></template>
|
||||||
|
{{ t('common.reset') }}
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-card>
|
</a-card>
|
||||||
|
|
||||||
@@ -971,6 +972,7 @@ onMounted(() => {
|
|||||||
type="dashed"
|
type="dashed"
|
||||||
@click.prevent="fnModalUploadImportOpen()"
|
@click.prevent="fnModalUploadImportOpen()"
|
||||||
v-perms:has="['system:user:import']"
|
v-perms:has="['system:user:import']"
|
||||||
|
v-if="false"
|
||||||
>
|
>
|
||||||
<template #icon><ImportOutlined /></template>
|
<template #icon><ImportOutlined /></template>
|
||||||
{{ t('common.import') }}
|
{{ t('common.import') }}
|
||||||
@@ -979,6 +981,7 @@ onMounted(() => {
|
|||||||
type="dashed"
|
type="dashed"
|
||||||
@click.prevent="fnExportList()"
|
@click.prevent="fnExportList()"
|
||||||
v-perms:has="['system:user:export']"
|
v-perms:has="['system:user:export']"
|
||||||
|
v-if="false"
|
||||||
>
|
>
|
||||||
<template #icon><ExportOutlined /></template>
|
<template #icon><ExportOutlined /></template>
|
||||||
{{ t('common.export') }}
|
{{ t('common.export') }}
|
||||||
@@ -1255,6 +1258,7 @@ onMounted(() => {
|
|||||||
name="deptId"
|
name="deptId"
|
||||||
:label-col="{ span: 3 }"
|
:label-col="{ span: 3 }"
|
||||||
:label-wrap="true"
|
:label-wrap="true"
|
||||||
|
v-if="false"
|
||||||
>
|
>
|
||||||
<a-tree-select
|
<a-tree-select
|
||||||
:value="modalState.from.deptId"
|
:value="modalState.from.deptId"
|
||||||
@@ -1274,7 +1278,7 @@ onMounted(() => {
|
|||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-row>
|
<a-row>
|
||||||
<a-col :lg="12" :md="12" :xs="24">
|
<a-col :lg="12" :md="12" :xs="24" v-if="false">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label="t('views.system.user.userWork')"
|
:label="t('views.system.user.userWork')"
|
||||||
name="postIds"
|
name="postIds"
|
||||||
@@ -1407,6 +1411,7 @@ onMounted(() => {
|
|||||||
:md="12"
|
:md="12"
|
||||||
:xs="24"
|
:xs="24"
|
||||||
v-perms:has="['system:user:editPost']"
|
v-perms:has="['system:user:editPost']"
|
||||||
|
v-if="false"
|
||||||
>
|
>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label="t('views.system.user.userWork')"
|
:label="t('views.system.user.userWork')"
|
||||||
@@ -1519,6 +1524,7 @@ onMounted(() => {
|
|||||||
:label="t('views.system.user.fromClass')"
|
:label="t('views.system.user.fromClass')"
|
||||||
name="deptId"
|
name="deptId"
|
||||||
:label-col="{ span: 3 }"
|
:label-col="{ span: 3 }"
|
||||||
|
v-if="false"
|
||||||
>
|
>
|
||||||
<a-tree-select
|
<a-tree-select
|
||||||
v-model:value="modalState.from.deptId"
|
v-model:value="modalState.from.deptId"
|
||||||
|
|||||||
339
src/views/tool/terminal-more/index.vue
Normal file
339
src/views/tool/terminal-more/index.vue
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { PageContainer } from 'antdv-pro-layout';
|
||||||
|
import { Modal } from 'ant-design-vue/es';
|
||||||
|
import { useFullscreen } from '@vueuse/core';
|
||||||
|
import { defineAsyncComponent, reactive, ref } from 'vue';
|
||||||
|
import { parseDuration } from '@/utils/date-utils';
|
||||||
|
import useI18n from '@/hooks/useI18n';
|
||||||
|
const { t } = useI18n();
|
||||||
|
const TerminalSSH = defineAsyncComponent(
|
||||||
|
() => import('@/components/TerminalSSH/index.vue')
|
||||||
|
);
|
||||||
|
const TerminalTelnet = defineAsyncComponent(
|
||||||
|
() => import('@/components/TerminalTelnet/index.vue')
|
||||||
|
);
|
||||||
|
const TerminalRedis = defineAsyncComponent(
|
||||||
|
() => import('@/components/TerminalRedis/index.vue')
|
||||||
|
);
|
||||||
|
const HostList = defineAsyncComponent(
|
||||||
|
() => import('./components/hostList.vue')
|
||||||
|
);
|
||||||
|
|
||||||
|
// 全屏
|
||||||
|
const terminalCard = ref<HTMLElement | null>(null);
|
||||||
|
const { isFullscreen, toggle } = useFullscreen(terminalCard);
|
||||||
|
|
||||||
|
/**主机对象信息状态类型 */
|
||||||
|
type HostStateType = {
|
||||||
|
/**显示主机列表 */
|
||||||
|
show: boolean;
|
||||||
|
/**加载等待 */
|
||||||
|
loading: boolean;
|
||||||
|
/**查询参数 */
|
||||||
|
params: {
|
||||||
|
pageNum: number;
|
||||||
|
pageSize: number;
|
||||||
|
};
|
||||||
|
/**数据总数 */
|
||||||
|
total: number;
|
||||||
|
data: Record<string, any>[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**主机对象信息状态 */
|
||||||
|
const hostState: HostStateType = reactive({
|
||||||
|
show: false,
|
||||||
|
loading: false,
|
||||||
|
params: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
},
|
||||||
|
total: 0,
|
||||||
|
data: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
/**连接主机 */
|
||||||
|
function fnConnectHost(data: Record<string, any>) {
|
||||||
|
const id = `${Date.now()}`;
|
||||||
|
tabState.panes.push({
|
||||||
|
id,
|
||||||
|
status: false,
|
||||||
|
host: data,
|
||||||
|
});
|
||||||
|
tabState.activeKey = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**标签对象信息状态类型 */
|
||||||
|
type TabStateType = {
|
||||||
|
/**激活选中 */
|
||||||
|
activeKey: string;
|
||||||
|
/**页签数据 */
|
||||||
|
panes: {
|
||||||
|
id: string;
|
||||||
|
status: boolean;
|
||||||
|
host: Record<string, any>;
|
||||||
|
connectStamp?: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**标签对象信息状态 */
|
||||||
|
const tabState: TabStateType = reactive({
|
||||||
|
activeKey: '0',
|
||||||
|
panes: [
|
||||||
|
{
|
||||||
|
id: '0',
|
||||||
|
host: {
|
||||||
|
id: 0,
|
||||||
|
title: t('views.tool.terminal.start'),
|
||||||
|
type: '0',
|
||||||
|
},
|
||||||
|
status: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终端连接状态
|
||||||
|
* @param data 主机连接结果
|
||||||
|
*/
|
||||||
|
function fnTerminalConnect(data: Record<string, any>) {
|
||||||
|
const { id, timeStamp } = data;
|
||||||
|
const seconds = timeStamp / 1000;
|
||||||
|
// 获取当前项下标
|
||||||
|
const tab = tabState.panes.find(item => item.id === id);
|
||||||
|
if (tab) {
|
||||||
|
tab.status = true;
|
||||||
|
tab.connectStamp = parseDuration(seconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终端关闭状态
|
||||||
|
* @param data 主机连接结果
|
||||||
|
*/
|
||||||
|
function fnTerminalClose(data: Record<string, any>) {
|
||||||
|
const { id } = data;
|
||||||
|
// 获取当前项下标
|
||||||
|
const tab = tabState.panes.find(item => item.id === id);
|
||||||
|
if (tab) {
|
||||||
|
tab.status = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标签更多菜单项
|
||||||
|
* @param key 菜单key
|
||||||
|
*/
|
||||||
|
function fnTabMenu(key: string | number) {
|
||||||
|
// 刷新当前
|
||||||
|
if (key === 'reload') {
|
||||||
|
const tabIndex = tabState.panes.findIndex(
|
||||||
|
item => item.id === tabState.activeKey
|
||||||
|
);
|
||||||
|
if (tabIndex) {
|
||||||
|
const tab = tabState.panes[tabIndex];
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('common.tipTitle'),
|
||||||
|
content: t('views.tool.terminal.reloadTip', {
|
||||||
|
num: `${tab.host.hostType} - ${tab.host.title}`,
|
||||||
|
}),
|
||||||
|
onOk() {
|
||||||
|
tabState.panes.splice(tabIndex, 1);
|
||||||
|
tab.host && fnConnectHost(tab.host);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 关闭当前
|
||||||
|
if (key === 'current') {
|
||||||
|
fnTabClose(tabState.activeKey);
|
||||||
|
}
|
||||||
|
// 关闭其他
|
||||||
|
if (key === 'other') {
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('common.tipTitle'),
|
||||||
|
content: t('views.tool.terminal.otherTip'),
|
||||||
|
onOk() {
|
||||||
|
hostState.show = false;
|
||||||
|
tabState.panes = tabState.panes.filter(
|
||||||
|
tab => tab.id === '0' || tab.id === tabState.activeKey
|
||||||
|
);
|
||||||
|
tabState.activeKey = tabState.activeKey;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 关闭全部
|
||||||
|
if (key === 'all') {
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('common.tipTitle'),
|
||||||
|
content: t('views.tool.terminal.allTip'),
|
||||||
|
onOk() {
|
||||||
|
hostState.show = false;
|
||||||
|
tabState.panes.splice(1);
|
||||||
|
tabState.activeKey = '0';
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导航标签关闭
|
||||||
|
* @param id 标签的key
|
||||||
|
*/
|
||||||
|
function fnTabClose(id: string) {
|
||||||
|
if (isFullscreen.value) toggle();
|
||||||
|
|
||||||
|
// 获取当前项下标
|
||||||
|
const tabIndex = tabState.panes.findIndex(tab => tab.id === id);
|
||||||
|
if (tabIndex === -1) return;
|
||||||
|
const item = tabState.panes[tabIndex];
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('common.tipTitle'),
|
||||||
|
content: t('views.tool.terminal.closeTip', {
|
||||||
|
num: `${item.host.hostType.toUpperCase()} - ${item.host.title}`,
|
||||||
|
}),
|
||||||
|
onOk() {
|
||||||
|
tabState.panes.splice(tabIndex, 1);
|
||||||
|
// 激活前一项标签
|
||||||
|
tabState.activeKey = tabState.panes[tabIndex - 1].id;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PageContainer>
|
||||||
|
<a-card
|
||||||
|
:bordered="false"
|
||||||
|
size="small"
|
||||||
|
:body-style="{ padding: '12px' }"
|
||||||
|
ref="terminalCard"
|
||||||
|
>
|
||||||
|
<a-tabs
|
||||||
|
class="terminal-tabs"
|
||||||
|
hide-add
|
||||||
|
size="small"
|
||||||
|
tab-position="top"
|
||||||
|
type="editable-card"
|
||||||
|
:tab-bar-gutter="8"
|
||||||
|
:tab-bar-style="{ margin: '0' }"
|
||||||
|
v-model:activeKey="tabState.activeKey"
|
||||||
|
@edit="(id:any) => fnTabClose(id)"
|
||||||
|
>
|
||||||
|
<a-tab-pane
|
||||||
|
v-for="pane in tabState.panes"
|
||||||
|
:key="pane.id"
|
||||||
|
:closable="pane.id !== '0'"
|
||||||
|
>
|
||||||
|
<template #tab>
|
||||||
|
<a-badge
|
||||||
|
:status="pane.status ? 'success' : 'error'"
|
||||||
|
:text="pane.host.title"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="pane-box">
|
||||||
|
<!-- 非开始页的ssh主机 -->
|
||||||
|
<TerminalSSH
|
||||||
|
v-if="pane.id !== '0' && pane.host.hostType === 'ssh'"
|
||||||
|
:id="pane.id"
|
||||||
|
:hostId="pane.host.id"
|
||||||
|
@connect="fnTerminalConnect"
|
||||||
|
@close="fnTerminalClose"
|
||||||
|
>
|
||||||
|
</TerminalSSH>
|
||||||
|
|
||||||
|
<!-- 非开始页的telnet主机 -->
|
||||||
|
<TerminalTelnet
|
||||||
|
v-if="pane.id !== '0' && pane.host.hostType === 'telnet'"
|
||||||
|
:id="pane.id"
|
||||||
|
:hostId="pane.host.id"
|
||||||
|
init-cmd="help"
|
||||||
|
:disable="true"
|
||||||
|
@connect="fnTerminalConnect"
|
||||||
|
@close="fnTerminalClose"
|
||||||
|
>
|
||||||
|
</TerminalTelnet>
|
||||||
|
|
||||||
|
<!-- 非开始页的redis主机 -->
|
||||||
|
<TerminalRedis
|
||||||
|
v-if="pane.id !== '0' && pane.host.hostType === 'redis'"
|
||||||
|
:id="pane.id"
|
||||||
|
:hostId="pane.host.id"
|
||||||
|
@connect="fnTerminalConnect"
|
||||||
|
@close="fnTerminalClose"
|
||||||
|
>
|
||||||
|
</TerminalRedis>
|
||||||
|
|
||||||
|
<!-- 开始页 -->
|
||||||
|
<div v-if="pane.id === '0'">
|
||||||
|
<!-- 主机列表 -->
|
||||||
|
<HostList
|
||||||
|
v-show="tabState.activeKey === '0'"
|
||||||
|
@modal="() => (isFullscreen ? toggle() : null)"
|
||||||
|
@link="fnConnectHost"
|
||||||
|
></HostList>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-tab-pane>
|
||||||
|
|
||||||
|
<template #rightExtra>
|
||||||
|
<a-space :size="8" align="center">
|
||||||
|
<a-tooltip placement="topRight">
|
||||||
|
<template #title>
|
||||||
|
{{ t('loayouts.rightContent.fullscreen') }}
|
||||||
|
</template>
|
||||||
|
<a-button
|
||||||
|
type="default"
|
||||||
|
shape="circle"
|
||||||
|
size="small"
|
||||||
|
style="color: inherit"
|
||||||
|
@click="toggle"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<FullscreenExitOutlined v-if="isFullscreen" />
|
||||||
|
<FullscreenOutlined v-else />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
<!-- 非开始页的更多操作 -->
|
||||||
|
<div v-show="tabState.activeKey !== '0'">
|
||||||
|
<a-tooltip placement="topRight">
|
||||||
|
<template #title>
|
||||||
|
{{ t('views.tool.terminal.more') }}
|
||||||
|
</template>
|
||||||
|
<a-dropdown trigger="click" placement="bottomRight">
|
||||||
|
<a-button type="ghost" shape="circle" size="small">
|
||||||
|
<template #icon><EllipsisOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
<template #overlay>
|
||||||
|
<a-menu @click="({ key }:any) => fnTabMenu(key)">
|
||||||
|
<a-menu-item key="reload">
|
||||||
|
{{ t('views.tool.terminal.reload') }}
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item key="current">
|
||||||
|
{{ t('views.tool.terminal.current') }}
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item key="other">
|
||||||
|
{{ t('views.tool.terminal.other') }}
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item key="all">
|
||||||
|
{{ t('views.tool.terminal.all') }}
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</template>
|
||||||
|
</a-dropdown>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</a-tabs>
|
||||||
|
</a-card>
|
||||||
|
</PageContainer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.pane-box {
|
||||||
|
height: calc(100vh - 200px);
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,203 +1,76 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { PageContainer } from 'antdv-pro-layout';
|
import { PageContainer } from 'antdv-pro-layout';
|
||||||
import { Modal } from 'ant-design-vue/es';
|
import { listNeHost } from '@/api/ne/neHost';
|
||||||
import { useFullscreen } from '@vueuse/core';
|
import { defineAsyncComponent, onMounted, reactive } from 'vue';
|
||||||
import { defineAsyncComponent, reactive, ref } from 'vue';
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
import { parseDuration } from '@/utils/date-utils';
|
|
||||||
import useI18n from '@/hooks/useI18n';
|
|
||||||
const { t } = useI18n();
|
|
||||||
const TerminalSSH = defineAsyncComponent(
|
const TerminalSSH = defineAsyncComponent(
|
||||||
() => import('@/components/TerminalSSH/index.vue')
|
() => import('@/components/TerminalSSH/index.vue')
|
||||||
);
|
);
|
||||||
const TerminalTelnet = defineAsyncComponent(
|
|
||||||
() => import('@/components/TerminalTelnet/index.vue')
|
|
||||||
);
|
|
||||||
const TerminalRedis = defineAsyncComponent(
|
|
||||||
() => import('@/components/TerminalRedis/index.vue')
|
|
||||||
);
|
|
||||||
const HostList = defineAsyncComponent(
|
|
||||||
() => import('./components/hostList.vue')
|
|
||||||
);
|
|
||||||
|
|
||||||
// 全屏
|
|
||||||
const terminalCard = ref<HTMLElement | null>(null);
|
|
||||||
const { isFullscreen, toggle } = useFullscreen(terminalCard);
|
|
||||||
|
|
||||||
/**主机对象信息状态类型 */
|
/**主机对象信息状态类型 */
|
||||||
type HostStateType = {
|
type HostStateType = {
|
||||||
/**显示主机列表 */
|
|
||||||
show: boolean;
|
|
||||||
/**加载等待 */
|
/**加载等待 */
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
/**查询参数 */
|
/**查询参数 */
|
||||||
params: {
|
params: {
|
||||||
pageNum: number;
|
/**主机类型 */
|
||||||
pageSize: number;
|
hostType: 'ssh';
|
||||||
|
/**分组 */
|
||||||
|
groupId: '1';
|
||||||
|
/**名称 */
|
||||||
|
title: 'OMC';
|
||||||
|
/**当前页数 */
|
||||||
|
pageNum: 1;
|
||||||
|
/**每页条数 */
|
||||||
|
pageSize: 10;
|
||||||
|
sortField: 'createTime';
|
||||||
|
sortOrder: 'desc';
|
||||||
};
|
};
|
||||||
/**数据总数 */
|
/**OMC主机 */
|
||||||
total: number;
|
host: Record<string, any>;
|
||||||
data: Record<string, any>[];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**主机对象信息状态 */
|
/**主机对象信息状态 */
|
||||||
const hostState: HostStateType = reactive({
|
const hostState: HostStateType = reactive({
|
||||||
show: false,
|
|
||||||
loading: false,
|
loading: false,
|
||||||
params: {
|
params: {
|
||||||
|
/**主机类型 */
|
||||||
|
hostType: 'ssh',
|
||||||
|
/**分组 */
|
||||||
|
groupId: '1',
|
||||||
|
/**名称 */
|
||||||
|
title: 'OMC',
|
||||||
|
/**当前页数 */
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 20,
|
/**每页条数 */
|
||||||
|
pageSize: 10,
|
||||||
|
sortField: 'createTime',
|
||||||
|
sortOrder: 'desc',
|
||||||
},
|
},
|
||||||
total: 0,
|
host: {},
|
||||||
data: [],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**连接主机 */
|
/**查询信息列表, pageNum初始页数 */
|
||||||
function fnConnectHost(data: Record<string, any>) {
|
function fnGetList() {
|
||||||
const id = `${Date.now()}`;
|
hostState.loading = true;
|
||||||
tabState.panes.push({
|
listNeHost(hostState.params)
|
||||||
id,
|
.then(res => {
|
||||||
status: false,
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
host: data,
|
const { total, rows } = res.data;
|
||||||
});
|
if (total > 0) {
|
||||||
tabState.activeKey = id;
|
hostState.host = rows[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hostState.loading = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**标签对象信息状态类型 */
|
onMounted(() => {
|
||||||
type TabStateType = {
|
// 获取列表数据
|
||||||
/**激活选中 */
|
fnGetList();
|
||||||
activeKey: string;
|
|
||||||
/**页签数据 */
|
|
||||||
panes: {
|
|
||||||
id: string;
|
|
||||||
status: boolean;
|
|
||||||
host: Record<string, any>;
|
|
||||||
connectStamp?: string;
|
|
||||||
}[];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**标签对象信息状态 */
|
|
||||||
const tabState: TabStateType = reactive({
|
|
||||||
activeKey: '0',
|
|
||||||
panes: [
|
|
||||||
{
|
|
||||||
id: '0',
|
|
||||||
host: {
|
|
||||||
id: 0,
|
|
||||||
title: t('views.tool.terminal.start'),
|
|
||||||
type: '0',
|
|
||||||
},
|
|
||||||
status: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* 终端连接状态
|
|
||||||
* @param data 主机连接结果
|
|
||||||
*/
|
|
||||||
function fnTerminalConnect(data: Record<string, any>) {
|
|
||||||
const { id, timeStamp } = data;
|
|
||||||
const seconds = timeStamp / 1000;
|
|
||||||
// 获取当前项下标
|
|
||||||
const tab = tabState.panes.find(item => item.id === id);
|
|
||||||
if (tab) {
|
|
||||||
tab.status = true;
|
|
||||||
tab.connectStamp = parseDuration(seconds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 终端关闭状态
|
|
||||||
* @param data 主机连接结果
|
|
||||||
*/
|
|
||||||
function fnTerminalClose(data: Record<string, any>) {
|
|
||||||
const { id } = data;
|
|
||||||
// 获取当前项下标
|
|
||||||
const tab = tabState.panes.find(item => item.id === id);
|
|
||||||
if (tab) {
|
|
||||||
tab.status = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 标签更多菜单项
|
|
||||||
* @param key 菜单key
|
|
||||||
*/
|
|
||||||
function fnTabMenu(key: string | number) {
|
|
||||||
// 刷新当前
|
|
||||||
if (key === 'reload') {
|
|
||||||
const tabIndex = tabState.panes.findIndex(
|
|
||||||
item => item.id === tabState.activeKey
|
|
||||||
);
|
|
||||||
if (tabIndex) {
|
|
||||||
const tab = tabState.panes[tabIndex];
|
|
||||||
Modal.confirm({
|
|
||||||
title: t('common.tipTitle'),
|
|
||||||
content: t('views.tool.terminal.reloadTip', {
|
|
||||||
num: `${tab.host.hostType} - ${tab.host.title}`,
|
|
||||||
}),
|
|
||||||
onOk() {
|
|
||||||
tabState.panes.splice(tabIndex, 1);
|
|
||||||
tab.host && fnConnectHost(tab.host);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 关闭当前
|
|
||||||
if (key === 'current') {
|
|
||||||
fnTabClose(tabState.activeKey);
|
|
||||||
}
|
|
||||||
// 关闭其他
|
|
||||||
if (key === 'other') {
|
|
||||||
Modal.confirm({
|
|
||||||
title: t('common.tipTitle'),
|
|
||||||
content: t('views.tool.terminal.otherTip'),
|
|
||||||
onOk() {
|
|
||||||
hostState.show = false;
|
|
||||||
tabState.panes = tabState.panes.filter(
|
|
||||||
tab => tab.id === '0' || tab.id === tabState.activeKey
|
|
||||||
);
|
|
||||||
tabState.activeKey = tabState.activeKey;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 关闭全部
|
|
||||||
if (key === 'all') {
|
|
||||||
Modal.confirm({
|
|
||||||
title: t('common.tipTitle'),
|
|
||||||
content: t('views.tool.terminal.allTip'),
|
|
||||||
onOk() {
|
|
||||||
hostState.show = false;
|
|
||||||
tabState.panes.splice(1);
|
|
||||||
tabState.activeKey = '0';
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导航标签关闭
|
|
||||||
* @param id 标签的key
|
|
||||||
*/
|
|
||||||
function fnTabClose(id: string) {
|
|
||||||
if (isFullscreen.value) toggle();
|
|
||||||
|
|
||||||
// 获取当前项下标
|
|
||||||
const tabIndex = tabState.panes.findIndex(tab => tab.id === id);
|
|
||||||
if (tabIndex === -1) return;
|
|
||||||
const item = tabState.panes[tabIndex];
|
|
||||||
Modal.confirm({
|
|
||||||
title: t('common.tipTitle'),
|
|
||||||
content: t('views.tool.terminal.closeTip', {
|
|
||||||
num: `${item.host.hostType.toUpperCase()} - ${item.host.title}`,
|
|
||||||
}),
|
|
||||||
onOk() {
|
|
||||||
tabState.panes.splice(tabIndex, 1);
|
|
||||||
// 激活前一项标签
|
|
||||||
tabState.activeKey = tabState.panes[tabIndex - 1].id;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -205,136 +78,13 @@ function fnTabClose(id: string) {
|
|||||||
<a-card
|
<a-card
|
||||||
:bordered="false"
|
:bordered="false"
|
||||||
size="small"
|
size="small"
|
||||||
:body-style="{ padding: '12px' }"
|
:body-style="{ padding: '12px', height: 'calc(100vh - 200px)' }"
|
||||||
ref="terminalCard"
|
:loading="hostState.loading"
|
||||||
>
|
>
|
||||||
<a-tabs
|
<TerminalSSH :id="hostState.host.title" :hostId="hostState.host.id">
|
||||||
class="terminal-tabs"
|
</TerminalSSH>
|
||||||
hide-add
|
|
||||||
size="small"
|
|
||||||
tab-position="top"
|
|
||||||
type="editable-card"
|
|
||||||
:tab-bar-gutter="8"
|
|
||||||
:tab-bar-style="{ margin: '0' }"
|
|
||||||
v-model:activeKey="tabState.activeKey"
|
|
||||||
@edit="(id:any) => fnTabClose(id)"
|
|
||||||
>
|
|
||||||
<a-tab-pane
|
|
||||||
v-for="pane in tabState.panes"
|
|
||||||
:key="pane.id"
|
|
||||||
:closable="pane.id !== '0'"
|
|
||||||
>
|
|
||||||
<template #tab>
|
|
||||||
<a-badge
|
|
||||||
:status="pane.status ? 'success' : 'error'"
|
|
||||||
:text="pane.host.title"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="pane-box">
|
|
||||||
<!-- 非开始页的ssh主机 -->
|
|
||||||
<TerminalSSH
|
|
||||||
v-if="pane.id !== '0' && pane.host.hostType === 'ssh'"
|
|
||||||
:id="pane.id"
|
|
||||||
:hostId="pane.host.id"
|
|
||||||
@connect="fnTerminalConnect"
|
|
||||||
@close="fnTerminalClose"
|
|
||||||
>
|
|
||||||
</TerminalSSH>
|
|
||||||
|
|
||||||
<!-- 非开始页的telnet主机 -->
|
|
||||||
<TerminalTelnet
|
|
||||||
v-if="pane.id !== '0' && pane.host.hostType === 'telnet'"
|
|
||||||
:id="pane.id"
|
|
||||||
:hostId="pane.host.id"
|
|
||||||
init-cmd="help"
|
|
||||||
:disable="true"
|
|
||||||
@connect="fnTerminalConnect"
|
|
||||||
@close="fnTerminalClose"
|
|
||||||
>
|
|
||||||
</TerminalTelnet>
|
|
||||||
|
|
||||||
<!-- 非开始页的redis主机 -->
|
|
||||||
<TerminalRedis
|
|
||||||
v-if="pane.id !== '0' && pane.host.hostType === 'redis'"
|
|
||||||
:id="pane.id"
|
|
||||||
:hostId="pane.host.id"
|
|
||||||
init-cmd="PING"
|
|
||||||
@connect="fnTerminalConnect"
|
|
||||||
@close="fnTerminalClose"
|
|
||||||
>
|
|
||||||
</TerminalRedis>
|
|
||||||
|
|
||||||
<!-- 开始页 -->
|
|
||||||
<div v-if="pane.id === '0'">
|
|
||||||
<!-- 主机列表 -->
|
|
||||||
<HostList
|
|
||||||
v-show="tabState.activeKey === '0'"
|
|
||||||
@modal="() => (isFullscreen ? toggle() : null)"
|
|
||||||
@link="fnConnectHost"
|
|
||||||
></HostList>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-tab-pane>
|
|
||||||
|
|
||||||
<template #rightExtra>
|
|
||||||
<a-space :size="8" align="center">
|
|
||||||
<a-tooltip placement="topRight">
|
|
||||||
<template #title>
|
|
||||||
{{ t('loayouts.rightContent.fullscreen') }}
|
|
||||||
</template>
|
|
||||||
<a-button
|
|
||||||
type="default"
|
|
||||||
shape="circle"
|
|
||||||
size="small"
|
|
||||||
style="color: inherit"
|
|
||||||
@click="toggle"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<FullscreenExitOutlined v-if="isFullscreen" />
|
|
||||||
<FullscreenOutlined v-else />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</a-tooltip>
|
|
||||||
<!-- 非开始页的更多操作 -->
|
|
||||||
<div v-show="tabState.activeKey !== '0'">
|
|
||||||
<a-tooltip placement="topRight">
|
|
||||||
<template #title>
|
|
||||||
{{ t('views.tool.terminal.more') }}
|
|
||||||
</template>
|
|
||||||
<a-dropdown trigger="click" placement="bottomRight">
|
|
||||||
<a-button type="ghost" shape="circle" size="small">
|
|
||||||
<template #icon><EllipsisOutlined /></template>
|
|
||||||
</a-button>
|
|
||||||
<template #overlay>
|
|
||||||
<a-menu @click="({ key }:any) => fnTabMenu(key)">
|
|
||||||
<a-menu-item key="reload">
|
|
||||||
{{ t('views.tool.terminal.reload') }}
|
|
||||||
</a-menu-item>
|
|
||||||
<a-menu-item key="current">
|
|
||||||
{{ t('views.tool.terminal.current') }}
|
|
||||||
</a-menu-item>
|
|
||||||
<a-menu-item key="other">
|
|
||||||
{{ t('views.tool.terminal.other') }}
|
|
||||||
</a-menu-item>
|
|
||||||
<a-menu-item key="all">
|
|
||||||
{{ t('views.tool.terminal.all') }}
|
|
||||||
</a-menu-item>
|
|
||||||
</a-menu>
|
|
||||||
</template>
|
|
||||||
</a-dropdown>
|
|
||||||
</a-tooltip>
|
|
||||||
</div>
|
|
||||||
</a-space>
|
|
||||||
</template>
|
|
||||||
</a-tabs>
|
|
||||||
</a-card>
|
</a-card>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped></style>
|
||||||
.pane-box {
|
|
||||||
height: calc(100vh - 200px);
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user