629 lines
17 KiB
Vue
629 lines
17 KiB
Vue
<script setup lang="ts">
|
|
import { reactive, onMounted, toRaw } from 'vue';
|
|
import { message, Form, Upload } from 'ant-design-vue/lib';
|
|
import useI18n from '@/hooks/useI18n';
|
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
|
import { NE_TYPE_LIST } from '@/constants/ne-constants';
|
|
import { ColumnsType } from 'ant-design-vue/lib/table';
|
|
import { installNeSoftware, listNeSoftware } from '@/api/ne/neSoftware';
|
|
import { parseDateToStr } from '@/utils/date-utils';
|
|
import { FileType } from 'ant-design-vue/lib/upload/interface';
|
|
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
|
|
import { uploadFileChunk } from '@/api/tool/file';
|
|
import { stepState } from '../hooks/useStep';
|
|
const { t } = useI18n();
|
|
|
|
/**表格字段列 */
|
|
let tableColumns: ColumnsType = [
|
|
{
|
|
title: t('common.rowId'),
|
|
dataIndex: 'id',
|
|
align: 'left',
|
|
width: 50,
|
|
},
|
|
{
|
|
title: 'neType',
|
|
dataIndex: 'neType',
|
|
align: 'left',
|
|
width: 100,
|
|
},
|
|
{
|
|
title: 'name',
|
|
dataIndex: 'name',
|
|
key: 'name',
|
|
align: 'left',
|
|
width: 300,
|
|
},
|
|
{
|
|
title: 'version',
|
|
dataIndex: 'version',
|
|
align: 'left',
|
|
width: 100,
|
|
},
|
|
{
|
|
title: 'description',
|
|
dataIndex: 'description',
|
|
key: 'description',
|
|
align: 'left',
|
|
ellipsis: true,
|
|
},
|
|
{
|
|
title: 'createTime',
|
|
dataIndex: 'createTime',
|
|
align: 'left',
|
|
width: 150,
|
|
customRender(opt) {
|
|
if (!opt.value) return '';
|
|
return parseDateToStr(+opt.value);
|
|
},
|
|
},
|
|
];
|
|
|
|
/**表格分页器参数 */
|
|
let tablePagination = reactive({
|
|
/**当前页数 */
|
|
current: 1,
|
|
/**每页条数 */
|
|
pageSize: 10,
|
|
/**默认的每页条数 */
|
|
defaultPageSize: 10,
|
|
/**指定每页可以显示多少条 */
|
|
pageSizeOptions: ['10', '20', '50', '100'],
|
|
/**只有一页时是否隐藏分页器 */
|
|
hideOnSinglePage: false,
|
|
/**是否可以快速跳转至某页 */
|
|
showQuickJumper: true,
|
|
/**是否可以改变 pageSize */
|
|
showSizeChanger: true,
|
|
/**数据总数 */
|
|
total: 0,
|
|
showTotal: (total: number) => t('common.tablePaginationTotal', { total }),
|
|
onChange: (page: number, pageSize: number) => {
|
|
tablePagination.current = page;
|
|
tablePagination.pageSize = pageSize;
|
|
tableState.queryParams.pageNum = page;
|
|
tableState.queryParams.pageSize = pageSize;
|
|
fnGetList();
|
|
},
|
|
});
|
|
|
|
/**表格状态类型 */
|
|
type TabeStateType = {
|
|
/**查询参数 */
|
|
queryParams: Record<string, any>;
|
|
/**加载等待 */
|
|
loading: boolean;
|
|
/**记录数据 */
|
|
data: object[];
|
|
/**勾选记录 */
|
|
selectedRowKeys: (string | number)[];
|
|
};
|
|
|
|
/**表格状态 */
|
|
let tableState: TabeStateType = reactive({
|
|
queryParams: {
|
|
neType: '',
|
|
pageNum: 1,
|
|
pageSize: 10,
|
|
},
|
|
loading: false,
|
|
data: [],
|
|
selectedRowKeys: [],
|
|
});
|
|
|
|
/**表格多选 */
|
|
function fnTableSelectedRowKeys(
|
|
keys: (string | number)[],
|
|
selectedRows: any[]
|
|
) {
|
|
tableState.selectedRowKeys = keys;
|
|
// 选择的表单数据填充
|
|
const row = selectedRows[0];
|
|
installState.from.neType = row.neType;
|
|
installState.from.name = row.name;
|
|
installState.from.path = row.path;
|
|
installState.from.version = row.version;
|
|
installState.from.description = row.description;
|
|
}
|
|
|
|
/**查询列表, pageNum初始页数 */
|
|
function fnGetList(pageNum?: number) {
|
|
if (tableState.loading) return;
|
|
tableState.loading = true;
|
|
if (pageNum) {
|
|
tableState.queryParams.pageNum = pageNum;
|
|
}
|
|
listNeSoftware(toRaw(tableState.queryParams)).then(res => {
|
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
|
|
// 取消勾选
|
|
if (tableState.selectedRowKeys.length > 0) {
|
|
tableState.selectedRowKeys = [];
|
|
}
|
|
tablePagination.total = res.total;
|
|
// 遍历处理资源情况数值
|
|
tableState.data = res.rows;
|
|
}
|
|
tableState.loading = false;
|
|
});
|
|
}
|
|
|
|
/**安装对象信息状态类型 */
|
|
type InstallStateType = {
|
|
/**步骤 */
|
|
setp: 'pkg' | 'preinput' | 'log';
|
|
/**步骤日志输出 */
|
|
setpLog: string;
|
|
/**文件操作类型 上传 or 选择 */
|
|
optionType: 'upload' | 'option';
|
|
/**表单数据 */
|
|
from: {
|
|
neType: string;
|
|
neId: string;
|
|
name: string;
|
|
path: string;
|
|
version: string;
|
|
description: string;
|
|
};
|
|
/**确定按钮 loading */
|
|
confirmLoading: boolean;
|
|
/**上传文件 */
|
|
uploadFiles: any[];
|
|
/**预输入 */
|
|
preinput: Record<string, any>;
|
|
};
|
|
|
|
/**安装对象信息状态 */
|
|
let installState: InstallStateType = reactive({
|
|
setp: 'pkg',
|
|
setpLog: '',
|
|
optionType: 'upload',
|
|
from: {
|
|
neType: '',
|
|
neId: '',
|
|
name: '',
|
|
path: '',
|
|
version: '',
|
|
description: '',
|
|
},
|
|
confirmLoading: false,
|
|
uploadFiles: [],
|
|
preinput: {
|
|
// IMS
|
|
pubIP: '192.168.5.57',
|
|
mcc: '001',
|
|
mnc: '01',
|
|
priIP: '172.16.16.51',
|
|
pisCSCF: 'true',
|
|
},
|
|
});
|
|
|
|
/**
|
|
* 表单修改网元类型
|
|
*/
|
|
function fnNeTypeChange(v: any) {
|
|
tableState.queryParams.neType = v;
|
|
if (installState.optionType === 'option') {
|
|
fnGetList(1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 表单修改文件操作类型
|
|
*/
|
|
function fnOptionTypeChange() {
|
|
if (installState.optionType === 'upload') {
|
|
installState.from.name = '';
|
|
installState.from.path = '';
|
|
installState.from.version = '';
|
|
installState.from.description = '';
|
|
}
|
|
if (installState.optionType === 'option') {
|
|
tableState.queryParams.neType = installState.from.neType;
|
|
fnGetList(1);
|
|
}
|
|
}
|
|
|
|
/**表单属性和校验规则 */
|
|
const installStateFrom = Form.useForm(
|
|
installState.from,
|
|
reactive({
|
|
neType: [
|
|
{
|
|
required: true,
|
|
min: 1,
|
|
max: 32,
|
|
message: t('views.configManage.softwareManage.neTypePlease'),
|
|
},
|
|
],
|
|
version: [
|
|
{
|
|
required: true,
|
|
min: 1,
|
|
max: 64,
|
|
message: t('views.configManage.softwareManage.versionPlease'),
|
|
},
|
|
],
|
|
path: [
|
|
{
|
|
required: true,
|
|
message: t('views.configManage.softwareManage.updateFilePlease'),
|
|
},
|
|
],
|
|
})
|
|
);
|
|
|
|
/**表单上传前检查或转换压缩 */
|
|
function fnBeforeUploadFile(file: FileType) {
|
|
if (installState.confirmLoading) return false;
|
|
const fileName = file.name;
|
|
const suff = fileName.substring(fileName.lastIndexOf('.'));
|
|
if (!['.deb', '.rpm'].includes(suff)) {
|
|
message.error(
|
|
t('views.configManage.softwareManage.onlyAble', {
|
|
fileText: '(.deb、.rpm)',
|
|
}),
|
|
3
|
|
);
|
|
return Upload.LIST_IGNORE;
|
|
}
|
|
// 根据给定的软件名取版本号 ims-r2.2312.x-ub22.deb
|
|
const matches = fileName.match(/([0-9.]+[0-9x]+)/);
|
|
if (matches) {
|
|
installState.from.version = matches[0];
|
|
}
|
|
const neTypeIndex = fileName.indexOf('-');
|
|
if (neTypeIndex !== -1) {
|
|
const neType = fileName.substring(0, neTypeIndex).toUpperCase();
|
|
if (installState.from.neType !== neType) {
|
|
message.error('请上传对应网元类型的安装包', 3);
|
|
return Upload.LIST_IGNORE;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**表单上传文件 */
|
|
function fnUploadFile(up: UploadRequestOption) {
|
|
// 发送请求
|
|
const hide = message.loading(t('common.loading'), 0);
|
|
installState.confirmLoading = true;
|
|
uploadFileChunk(up.file as File, 5, 'software')
|
|
.then(res => {
|
|
if (res.code === RESULT_CODE_SUCCESS) {
|
|
message.success('上传成功', 3);
|
|
// 改为完成状态
|
|
const file = installState.uploadFiles[0];
|
|
file.percent = 100;
|
|
file.status = 'done';
|
|
// 预置到表单
|
|
const { fileName, originalFileName } = res.data;
|
|
installState.from.name = originalFileName;
|
|
installState.from.path = fileName;
|
|
} else {
|
|
message.error(res.msg, 3);
|
|
}
|
|
})
|
|
.finally(() => {
|
|
hide();
|
|
installState.confirmLoading = false;
|
|
});
|
|
}
|
|
|
|
/**软件包检查 */
|
|
function fnRunCheck() {
|
|
if (installState.confirmLoading) return;
|
|
const hide = message.loading(t('common.loading'), 0);
|
|
installStateFrom
|
|
.validate()
|
|
.then(() => {
|
|
installState.setp = 'preinput';
|
|
})
|
|
.catch(e => {
|
|
message.error(t('common.errorFields', { num: e.errorFields.length }), 3);
|
|
})
|
|
.finally(() => {
|
|
hide();
|
|
installState.confirmLoading = false;
|
|
});
|
|
}
|
|
|
|
/**开始安装 */
|
|
function fnInstall() {
|
|
if (installState.confirmLoading) return;
|
|
installState.confirmLoading = true;
|
|
const hide = message.loading(t('common.loading'), 0);
|
|
const from = toRaw(installState.from);
|
|
const preinput = toRaw(installState.preinput);
|
|
installNeSoftware({
|
|
software: from,
|
|
preinput: preinput,
|
|
})
|
|
.then(res => {
|
|
if (res.code === RESULT_CODE_SUCCESS) {
|
|
installState.setp = 'log';
|
|
installState.setpLog = res.data;
|
|
message.success('软件安装成功', 3);
|
|
// 记录当前步骤状态信息
|
|
stepState.states[stepState.current] = {
|
|
from: from,
|
|
preinput: preinput,
|
|
};
|
|
stepState.stepNext = true;
|
|
} else {
|
|
message.error(res.msg, 3);
|
|
}
|
|
})
|
|
.finally(() => {
|
|
hide();
|
|
installState.confirmLoading = false;
|
|
});
|
|
}
|
|
|
|
/**重新安装 */
|
|
function fnInstallReset() {
|
|
installState.setp = 'pkg';
|
|
installState.optionType = 'option';
|
|
}
|
|
|
|
onMounted(() => {
|
|
// 读取步骤:网元信息
|
|
const stepPrevFrom = stepState.states[1];
|
|
if (stepPrevFrom && stepPrevFrom.from) {
|
|
installState.from.neType = stepPrevFrom.from.neType;
|
|
installState.from.neId = stepPrevFrom.from.neId;
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<a-form
|
|
name="installStateFrom"
|
|
layout="horizontal"
|
|
:label-col="{ span: 3 }"
|
|
:wrapper-col="{ span: 8 }"
|
|
:label-wrap="true"
|
|
>
|
|
<div>---- 安装软件包</div>
|
|
|
|
<template v-if="installState.setp === 'pkg'">
|
|
<a-form-item
|
|
:label="t('views.configManage.softwareManage.neType')"
|
|
name="neType"
|
|
v-bind="installStateFrom.validateInfos.neType"
|
|
>
|
|
<a-auto-complete
|
|
v-model:value="installState.from.neType"
|
|
:disabled="true"
|
|
:options="NE_TYPE_LIST.map(v => ({ value: v }))"
|
|
@change="fnNeTypeChange"
|
|
>
|
|
<a-input
|
|
allow-clear
|
|
:placeholder="t('common.inputPlease')"
|
|
:maxlength="32"
|
|
:disabled="true"
|
|
>
|
|
<template #prefix>
|
|
<a-tooltip placement="topLeft">
|
|
<template #title>
|
|
{{ t('views.configManage.neManage.neTypeTip') }}
|
|
</template>
|
|
<InfoCircleOutlined style="color: rgba(0, 0, 0, 0.45)" />
|
|
</a-tooltip>
|
|
</template>
|
|
</a-input>
|
|
</a-auto-complete>
|
|
</a-form-item>
|
|
|
|
<a-form-item label="软件来源" name="optionType">
|
|
<a-radio-group
|
|
v-model:value="installState.optionType"
|
|
button-style="solid"
|
|
@change="fnOptionTypeChange"
|
|
:disabled="installState.confirmLoading"
|
|
>
|
|
<a-radio-button value="upload">新上传</a-radio-button>
|
|
<a-radio-button value="option">已上传</a-radio-button>
|
|
</a-radio-group>
|
|
</a-form-item>
|
|
|
|
<!-- 重新上传 -->
|
|
<template v-if="installState.optionType === 'upload'">
|
|
<a-form-item
|
|
:label="t('views.configManage.softwareManage.version')"
|
|
name="version"
|
|
v-bind="installStateFrom.validateInfos.version"
|
|
>
|
|
<a-input
|
|
v-model:value="installState.from.version"
|
|
allow-clear
|
|
:placeholder="t('views.configManage.softwareManage.versionPlease')"
|
|
></a-input>
|
|
</a-form-item>
|
|
<a-form-item
|
|
:label="t('views.configManage.softwareManage.updateComment')"
|
|
name="description"
|
|
v-bind="installStateFrom.validateInfos.description"
|
|
>
|
|
<a-textarea
|
|
v-model:value="installState.from.description"
|
|
:auto-size="{ minRows: 1, maxRows: 4 }"
|
|
:maxlength="500"
|
|
:show-count="true"
|
|
:placeholder="
|
|
t('views.configManage.softwareManage.updateCommentPlease')
|
|
"
|
|
/>
|
|
</a-form-item>
|
|
<a-form-item
|
|
:label="t('views.configManage.softwareManage.updateFile')"
|
|
name="file"
|
|
v-bind="installStateFrom.validateInfos.path"
|
|
>
|
|
<a-upload
|
|
name="file"
|
|
v-model:file-list="installState.uploadFiles"
|
|
accept=".rpm,.deb"
|
|
list-type="text"
|
|
:max-count="1"
|
|
:show-upload-list="{
|
|
showPreviewIcon: false,
|
|
showRemoveIcon: false,
|
|
showDownloadIcon: false,
|
|
}"
|
|
:before-upload="fnBeforeUploadFile"
|
|
:custom-request="fnUploadFile"
|
|
:disabled="installState.confirmLoading"
|
|
>
|
|
<a-button type="default" :disabled="installState.confirmLoading">
|
|
{{ t('views.configManage.softwareManage.selectFile') }}
|
|
</a-button>
|
|
</a-upload>
|
|
</a-form-item>
|
|
</template>
|
|
|
|
<!-- 选择已上传 -->
|
|
<template v-if="installState.optionType === 'option'">
|
|
<a-form-item label="选择记录" name="option" :wrapper-col="{ span: 24 }">
|
|
<a-table
|
|
class="table"
|
|
row-key="id"
|
|
:columns="tableColumns"
|
|
:loading="tableState.loading"
|
|
:data-source="tableState.data"
|
|
:pagination="tablePagination"
|
|
size="small"
|
|
:scroll="{ x: tableColumns.length * 100, y: '400px' }"
|
|
:row-selection="{
|
|
type: 'radio',
|
|
columnWidth: '48px',
|
|
selectedRowKeys: tableState.selectedRowKeys,
|
|
onChange: fnTableSelectedRowKeys,
|
|
}"
|
|
>
|
|
<template #bodyCell="{ column, record }">
|
|
<template v-if="column.key === 'name'">
|
|
<a-tooltip placement="topLeft">
|
|
<template #title>{{ record.path }}</template>
|
|
<div style="cursor: pointer">{{ record.name }}</div>
|
|
</a-tooltip>
|
|
</template>
|
|
<template v-if="column.key === 'description'">
|
|
<a-tooltip placement="topLeft">
|
|
<template #title>{{ record.description }}</template>
|
|
<div style="cursor: pointer">{{ record.description }}</div>
|
|
</a-tooltip>
|
|
</template>
|
|
</template>
|
|
</a-table>
|
|
</a-form-item>
|
|
</template>
|
|
|
|
<a-form-item :wrapper-col="{ span: 14, offset: 3 }">
|
|
<a-button
|
|
type="primary"
|
|
html-type="submit"
|
|
@click="fnRunCheck()"
|
|
:loading="installState.confirmLoading"
|
|
>
|
|
安装检查
|
|
</a-button>
|
|
</a-form-item>
|
|
</template>
|
|
|
|
<div>--- 安装前预输入</div>
|
|
|
|
<template v-if="installState.setp === 'preinput'">
|
|
<a-form-item
|
|
name="info"
|
|
label="安装前预输入"
|
|
:label-col="{ span: 3 }"
|
|
:label-wrap="true"
|
|
>
|
|
<div style="align-items: center">-----</div>
|
|
</a-form-item>
|
|
|
|
<!-- IMS 预输入 -->
|
|
<template v-if="installState.from.neType === 'IMS'">
|
|
<a-form-item label="P/I/S-CSCF Config" name="pisCSCF">
|
|
<a-input
|
|
v-model:value="installState.preinput.pisCSCF"
|
|
allow-clear
|
|
placeholder="P/I/S-CSCF Config"
|
|
></a-input>
|
|
</a-form-item>
|
|
<a-form-item label="modipplmn IP" name="pubIP">
|
|
<a-input
|
|
v-model:value="installState.preinput.pubIP"
|
|
allow-clear
|
|
placeholder="IMS modipplmn IP"
|
|
></a-input>
|
|
</a-form-item>
|
|
<a-form-item label="modipplmn mcc" name="mcc">
|
|
<a-input
|
|
v-model:value="installState.preinput.mcc"
|
|
allow-clear
|
|
placeholder="IMS modipplmn mcc"
|
|
></a-input>
|
|
</a-form-item>
|
|
<a-form-item label="modipplmn mnc" name="mnc">
|
|
<a-input
|
|
v-model:value="installState.preinput.mnc"
|
|
allow-clear
|
|
placeholder="IMS modipplmn mnc"
|
|
></a-input>
|
|
</a-form-item>
|
|
<a-form-item label="modintraip priIP" name="priIP">
|
|
<a-input
|
|
v-model:value="installState.preinput.priIP"
|
|
allow-clear
|
|
placeholder="IMS modintraip priIP"
|
|
></a-input>
|
|
</a-form-item>
|
|
</template>
|
|
|
|
<a-form-item :wrapper-col="{ span: 14, offset: 3 }">
|
|
<a-button
|
|
type="primary"
|
|
html-type="submit"
|
|
@click="fnInstall()"
|
|
:loading="installState.confirmLoading"
|
|
>
|
|
开始安装
|
|
</a-button>
|
|
</a-form-item>
|
|
</template>
|
|
|
|
<div>---- 安装进行信息</div>
|
|
|
|
<template v-if="installState.setp === 'log'">
|
|
<a-form-item
|
|
name="info"
|
|
label="安装日志"
|
|
:label-col="{ span: 3 }"
|
|
:wrapper-col="{ span: 24 }"
|
|
:label-wrap="true"
|
|
>
|
|
<TerminalText
|
|
id="installLog"
|
|
:rows="28"
|
|
:value="installState.setpLog"
|
|
></TerminalText>
|
|
</a-form-item>
|
|
|
|
<a-form-item :wrapper-col="{ span: 14, offset: 3 }">
|
|
<a-button
|
|
type="primary"
|
|
html-type="submit"
|
|
@click="fnInstallReset()"
|
|
:loading="installState.confirmLoading"
|
|
>
|
|
返回重新选择安装
|
|
</a-button>
|
|
</a-form-item>
|
|
</template>
|
|
</a-form>
|
|
</template>
|
|
|
|
<style lang="less" scoped></style>
|