Files
fe.ems.vue3/src/views/configManage/configParamForm/index.vue
2023-11-15 10:23:19 +08:00

1719 lines
54 KiB
Vue

<script setup lang="ts">
import { reactive, ref, onMounted } from 'vue';
import { PageContainer } from '@ant-design-vue/pro-layout';
import { message } from 'ant-design-vue/lib';
import useI18n from '@/hooks/useI18n';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import {
getParamConfigTopTab,
getParamConfigInfoForm,
updateParamConfigInfo,
delParamConfigInfo,
addParamConfigInfo,
} from '@/api/configManage/configParam';
import { TabPosition } from 'ant-design-vue/lib/tabs/src/interface';
import useNeInfoStore from '@/store/modules/neinfo';
import { toRaw } from 'vue';
import { regExpIPv4, regExpIPv6 } from '@/utils/regular-utils';
import { SizeType } from 'ant-design-vue/lib/config-provider';
const { t } = useI18n();
/**网元参数 */
let neCascaderOtions = ref<Record<string, any>[]>([]);
/**网元类型选择 type,id */
let neTypeSelect = ref<string[]>(['', '']);
/**tab标签栏类型 */
type TabStateType = {
/**标签方向 */
tabPosition: TabPosition;
/**标签项 */
tabNames: Record<string, any>[];
/**标签激活项 */
tabActiveTopTag: string;
/**标签项类型 */
tabType: 'list' | 'array';
/**加载等待 */
loading: boolean;
};
/**tab标签栏属性 */
let tabState: TabStateType = reactive({
tabPosition: 'top',
tabNames: [],
tabActiveTopTag: '',
tabType: 'list',
loading: false,
});
/**tab标签栏标签点击监听 */
function fnTabActiveTopTag(key: string | number) {
if (tabState.loading) return;
listState.data = [];
arrayState.data = [];
tabState.loading = true;
if (key !== '#') {
tabState.tabActiveTopTag = key as string;
}
// 获取数据
const neType = neTypeSelect.value[0];
const neId = neTypeSelect.value[1];
const topTag = tabState.tabActiveTopTag;
getParamConfigInfoForm(neType, topTag, neId)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS && res.data.type) {
tabState.tabActiveTopTag = topTag; // 激活当前数据项
tabState.loading = false;
tabState.tabType = res.data.type;
if (res.data.type === 'list') {
listState.data = res.data.data;
listEditClose();
}
if (res.data.type === 'array') {
arrayState.data = res.data.data;
arrayState.dataRule = res.data.dataRule;
arrayState.collapseActiveKey = [];
arrayEditClose();
}
} else {
message.warning({
content: t('common.noData'),
duration: 3,
});
}
})
.catch(err => {
console.log(err);
});
}
/**查询配置Tag标签 */
function fnGetParamConfigTopTab() {
const neType = neTypeSelect.value[0];
if (!neType) {
message.warning({
content: t('views.configManage.configParamForm.neTypePleace'),
duration: 3,
});
return;
}
// 获取数据
getParamConfigTopTab(neType).then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
tabState.tabNames = res.data;
// 取首个tag
if (res.data.length > 0) {
const topTag = res.data[0].topTag;
fnTabActiveTopTag(topTag);
}
} else {
message.warning({
content: t('views.configManage.configParamForm.noConfigData'),
duration: 3,
});
}
});
}
/**单列表状态类型 */
type ListStateType = {
/**紧凑型 */
size: SizeType;
/**单列记录字段 */
columns: Record<string, any>[];
/**单列记录数据 */
data: Record<string, any>[];
/**编辑行记录 */
editRecord: Record<string, any>;
};
/**单列表状态 */
let listState: ListStateType = reactive({
size: 'middle',
columns: [
{
title: 'Key',
dataIndex: 'display',
align: 'left',
width: '30%',
},
{
title: 'Value',
dataIndex: 'value',
align: 'left',
width: '70%',
},
],
data: [],
editRecord: {},
});
/**单列表编辑 */
function listEdit(row: Record<string, any>) {
listState.editRecord = Object.assign({}, row);
}
/**单列表编辑关闭 */
function listEditClose() {
listState.editRecord = {};
}
/**单列表编辑确认 */
function listEditOk() {
const from = toRaw(listState.editRecord);
// 检查规则
const [ok, msg] = ruleVerification(from);
if (!ok) {
message.warning({
content: `${msg}`,
duration: 3,
});
return;
}
// 发送
const hide = message.loading({ content: t('common.loading') });
let data = {
[from['name']]: from['value'],
};
updateParamConfigInfo(
'list',
{
neType: neTypeSelect.value[0],
neId: neTypeSelect.value[1],
topTag: tabState.tabActiveTopTag,
},
data
)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: t('views.configManage.configParamForm.updateValue', {
num: from['display'],
}),
duration: 3,
});
// 改变表格数据
const item = listState.data.filter(
(item: Record<string, any>) => from['name'] === item['name']
)[0];
if (item) {
Object.assign(item, listState.editRecord);
}
} else {
message.warning({
content: t('views.configManage.configParamForm.updateValueErr'),
duration: 3,
});
}
})
.finally(() => {
hide();
listState.editRecord = {};
});
}
/**多列列表状态类型 */
type ArrayStateType = {
/**面板激活项 */
collapseActiveKey: string[];
/**多列记录数据 */
data: Record<string, any>[];
/**多列记录规则 */
dataRule: Record<string, any>;
/**新增行记录Index 编辑-1/新增>=0 */
newIndex: number;
/**编辑行Key值 */
editKey: number | string;
/**编辑行记录 */
editRecord: Record<string, any>;
};
/**多列列表状态 */
let arrayState: ArrayStateType = reactive({
collapseActiveKey: [],
data: [],
dataRule: {},
newIndex: -2,
editKey: -1,
editRecord: {},
});
/**多列表编辑 */
function arrayEdit(item: Record<string, any>, index: number) {
console.log(item, index);
const row: Record<string, any> = {};
for (const v of item.record) {
row[v.name] = Object.assign({}, v);
}
arrayState.editRecord = row;
arrayState.editKey = item.key;
arrayState.newIndex = index;
// 面板
const hasIndex = arrayState.collapseActiveKey.indexOf(`${item.key}`);
if (hasIndex === -1) {
arrayState.collapseActiveKey.push(`${item.key}`);
} else {
// tableState.collapseActiveKey.splice(hasIndex, 1);
}
// 关闭嵌套
arrayChildExpandClose();
}
/**多列表编辑关闭 */
function arrayEditClose() {
arrayState.editRecord = {};
arrayState.newIndex = -3;
arrayState.editKey = -1;
arrayChildEditClose();
}
/**多列表编辑确认 */
function arrayEditOk() {
const from = toRaw(arrayState.editRecord);
const loc = from['index']['value'];
const neType = neTypeSelect.value[0];
// 遍历提取属性和值
let data: Record<string, any> = {};
for (const key in from) {
// 子嵌套的不插入
if (from[key]['array']) {
continue;
}
// 检查规则
const [ok, msg] = ruleVerification(from[key]);
if (!ok) {
message.warning({
content: `${msg}`,
duration: 3,
});
return;
}
data[key] = from[key]['value'];
}
// 发送
const hide = message.loading({ content: t('common.loading') });
updateParamConfigInfo(
'array',
{
neType: neType,
neId: neTypeSelect.value[1],
topTag: tabState.tabActiveTopTag,
loc,
},
data
)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: t('views.configManage.configParamForm.updateItem', {
num: loc,
}),
duration: 3,
});
fnTabActiveTopTag('#');
} else {
message.warning({
content: t('views.configManage.configParamForm.updateItemErr', {
num: loc,
}),
duration: 3,
});
}
})
.finally(() => {
hide();
arrayEditClose();
});
}
/**多列表删除单行 */
function arrayDelete(row: Record<string, any>) {
const index = row.key;
delParamConfigInfo({
neType: neTypeSelect.value[0],
neId: neTypeSelect.value[1],
topTag: tabState.tabActiveTopTag,
loc: index,
}).then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: t('views.configManage.configParamForm.delItemOk', {
num: index,
}),
duration: 2,
});
fnTabActiveTopTag('#');
} else {
message.error({
content: `${res.msg}`,
duration: 2,
});
}
});
}
/**多列表新增单行 */
function arrayAdd() {
const from = arrayAddInit(arrayState.data, arrayState.dataRule);
// 处理信息
const row: Record<string, any> = {};
for (const v of from.record) {
if (Array.isArray(v.array)) {
continue;
}
row[v.name] = Object.assign({}, v);
}
modalState.from = row;
modalState.type = 'array';
modalState.title = from.title;
modalState.key = from.key;
modalState.data = from.record.filter((v: any) => !Array.isArray(v.array));
modalState.visibleByAdd = true;
}
/**多列表新增单行确认 */
function arrayAddOk(from: Record<string, any>) {
const index = from['index']['value'];
const neType = neTypeSelect.value[0];
// 遍历提取属性和值
let data: Record<string, any> = {};
for (const key in from) {
// 子嵌套的不插入
if (from[key]['array']) {
continue;
}
// 检查规则
const [ok, msg] = ruleVerification(from[key]);
if (!ok) {
message.warning({
content: `${msg}`,
duration: 3,
});
return;
}
data[key] = from[key]['value'];
}
// 发送
const hide = message.loading({ content: t('common.loading') });
addParamConfigInfo(
{
neType: neType,
neId: neTypeSelect.value[1],
topTag: tabState.tabActiveTopTag,
loc: index,
},
data
)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: t('views.configManage.configParamForm.addItemOk', {
num: index,
}),
duration: 3,
});
fnTabActiveTopTag('#');
} else {
message.warning({
content: t('views.configManage.configParamForm.addItemErr'),
duration: 3,
});
}
})
.finally(() => {
hide();
fnModalCancel();
arrayEditClose();
});
}
/**多列嵌套列表状态类型 */
type ArrayChildStateType = {
/**标题 */
title: string;
/**层级index */
loc: string;
/**面板激活项 */
collapseActiveKey: string[];
/**多列嵌套记录数据 */
data: Record<string, any>[];
/**多列嵌套记录规则 */
dataRule: Record<string, any>;
/**新增嵌套行记录Index 编辑-1/新增>=0 */
newIndex: number;
/**编辑嵌套行Key值 */
editKey: number | string;
/**编辑嵌套行记录 */
editRecord: Record<string, any>;
};
/**表格状态 */
let arrayChildState: ArrayChildStateType = reactive({
title: '',
loc: '',
collapseActiveKey: [],
data: [],
dataRule: {},
newIndex: -2,
editKey: -1,
editRecord: {},
});
/**多列表展开嵌套行 */
function arrayChildExpand(key: number | string, row: Record<string, any>) {
const loc = key;
arrayChildState.loc = '';
const from = Object.assign({}, JSON.parse(JSON.stringify(row)));
// 无数据时
if (!Array.isArray(from.value)) {
from.value = [];
}
const dataArr = Object.freeze(from.value);
const ruleArr = Object.freeze(from.array);
// 列表项数据
const dataArray: Record<string, any>[] = [];
for (const item of dataArr) {
const index = item['index'];
let record: Record<string, any>[] = [];
for (const key of Object.keys(item)) {
// 规则为准
for (const rule of ruleArr) {
if (rule['name'] === key) {
const ruleItem = Object.assign({ optional: 'true' }, rule, {
value: item[key],
});
record.push(ruleItem);
break;
}
}
}
// dataArray.push(record);
dataArray.push({ title: `Index-${index}`, key: index, record });
}
arrayChildState.data = dataArray;
// 无数据时,用于新增
arrayChildState.dataRule = {
title: `Index-0`,
key: 0,
record: [ruleArr],
};
arrayChildState.loc = `${loc}/${from['name']}`;
arrayChildState.newIndex = -3;
// 设置展开列表标题
arrayChildState.title = `${from['display']}`;
// 关闭默认展开
arrayChildState.collapseActiveKey = [];
}
/**多列表展开嵌套行 */
function arrayChildExpandClose() {
arrayChildState.title = '';
arrayChildEditClose();
}
/**多列表嵌套行编辑 */
function arrayChildEdit(item: Record<string, any>, index: number) {
console.log(item, index);
const row: Record<string, any> = {};
for (const v of item.record) {
row[v.name] = Object.assign({}, v);
}
arrayChildState.editRecord = row;
arrayChildState.editKey = item.key;
arrayChildState.newIndex = index;
// 面板
const hasIndex = arrayChildState.collapseActiveKey.indexOf(`${item.key}`);
if (hasIndex === -1) {
arrayChildState.collapseActiveKey.push(`${item.key}`);
} else {
// arrayChildState.collapseActiveKey.splice(hasIndex, 1);
}
}
/**多列表嵌套行编辑关闭 */
function arrayChildEditClose() {
arrayChildState.editRecord = {};
arrayChildState.editKey = -1;
arrayChildState.newIndex = -3;
}
/**多列表嵌套行编辑确认 */
function arrayChildEditOk() {
const from = toRaw(arrayChildState.editRecord);
const index = from['index']['value'];
const loc = `${arrayChildState.loc}/${index}`;
const neType = neTypeSelect.value[0];
let data: Record<string, any> = {};
for (const key in from) {
// 子嵌套的不插入
if (from[key]['array']) {
continue;
}
// 检查规则
const [ok, msg] = ruleVerification(from[key]);
if (!ok) {
message.warning({
content: `${msg}`,
duration: 3,
});
return;
}
data[key] = from[key]['value'];
}
// 发送
const hide = message.loading({ content: t('common.loading') });
updateParamConfigInfo(
'array',
{
neType: neType,
neId: neTypeSelect.value[1],
topTag: tabState.tabActiveTopTag,
loc,
},
data
)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: t('views.configManage.configParamForm.updateItem', {
num: index,
}),
duration: 3,
});
fnTabActiveTopTag('#');
} else {
message.warning({
content: t('views.configManage.configParamForm.updateItemErr'),
duration: 3,
});
}
})
.finally(() => {
hide();
arrayChildExpandClose();
});
}
/**多列表嵌套行删除单行 */
function arrayChildDelete(row: Record<string, any>) {
const index = row.key;
const loc = `${arrayChildState.loc}/${index}`;
delParamConfigInfo({
neType: neTypeSelect.value[0],
neId: neTypeSelect.value[1],
topTag: tabState.tabActiveTopTag,
loc,
}).then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: t('views.configManage.configParamForm.delItemOk', {
num: index,
}),
duration: 2,
});
arrayChildExpandClose();
fnTabActiveTopTag('#');
} else {
message.error({
content: `${res.msg}`,
duration: 2,
});
}
});
}
/**多列表嵌套行新增单行 */
function arrayChildAdd() {
const from = arrayAddInit(arrayChildState.data, arrayChildState.dataRule);
// 处理信息
const row: Record<string, any> = {};
for (const v of from.record) {
if (Array.isArray(v.array)) {
continue;
}
row[v.name] = Object.assign({}, v);
}
modalState.from = row;
modalState.type = 'arrayChild';
modalState.title = from.title;
modalState.key = from.key;
modalState.data = from.record.filter((v: any) => !Array.isArray(v.array));
modalState.visibleByAdd = true;
}
/**多列表新增单行确认 */
function arrayChildAddOk(from: Record<string, any>) {
const index = from['index']['value'];
const loc = `${arrayChildState.loc}/${index}`;
const neType = neTypeSelect.value[0];
let data: Record<string, any> = {};
for (const key in from) {
// 子嵌套的不插入
if (from[key]['array']) {
continue;
}
// 检查规则
const [ok, msg] = ruleVerification(from[key]);
if (!ok) {
message.warning({
content: `${msg}`,
duration: 3,
});
return;
}
data[key] = from[key]['value'];
}
// 发送
const hide = message.loading({ content: t('common.loading') });
addParamConfigInfo(
{
neType: neType,
neId: neTypeSelect.value[1],
topTag: tabState.tabActiveTopTag,
loc,
},
data
)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: t('views.configManage.configParamForm.addItemOk', {
num: index,
}),
duration: 3,
});
fnTabActiveTopTag('#');
} else {
message.warning({
content: t('views.configManage.configParamForm.addItemErr'),
duration: 3,
});
}
})
.finally(() => {
hide();
fnModalCancel();
arrayChildExpandClose();
});
}
/**多列表新增行数据初始化 */
function arrayAddInit(data: any[], dataRule: any) {
const len = data.length;
let lastItme: Record<string, any> = {};
let newIndex = 0;
// 无数据时生成临时记录
if (len === 0) {
lastItme = dataRule;
} else {
lastItme = data[len - 1];
}
const from = Object.assign({}, JSON.parse(JSON.stringify(lastItme)));
for (const row of from.record) {
const value = row.value;
if (row.name === 'index') {
if (value !== '') {
newIndex = parseInt(value) + 1;
}
if (isNaN(newIndex)) {
newIndex = 0;
}
row.value = newIndex;
from.key = newIndex;
from.title = `Index-${newIndex}`;
continue;
}
// 子嵌套的不初始
if (row.array) {
row.value = null;
continue;
}
const type = row.type;
const filter = row.filter;
switch (type) {
case 'int':
if (filter && filter.indexOf('~') !== -1) {
const filterArr = filter.split('~');
const minInt = parseInt(filterArr[0]);
row.value = minInt;
} else {
row.value = 0;
}
break;
case 'enum':
if (filter && filter.indexOf('{') === 0) {
let filterJson: Record<string, any> = {};
try {
filterJson = JSON.parse(filter); //string---json
} catch (error) {
console.error(error);
}
row.value = Object.keys(filterJson)[0];
} else {
row.value = '0';
}
break;
case 'bool':
if (filter && filter.indexOf('{') === 0) {
let filterJson: Record<string, any> = {};
try {
filterJson = JSON.parse(filter); //string---json
} catch (error) {
console.error(error);
}
row.value = Object.keys(filterJson)[0];
} else {
row.value = false;
}
break;
case 'ipv4':
case 'ipv6':
case 'regex':
default:
row.value = '';
break;
}
}
return from;
}
/**规则校验 */
function ruleVerification(row: Record<string, any>): (string | boolean)[] {
let result = [true, ''];
const type = row.type;
const value = row.value;
const filter = row.filter;
const display = row.display;
// 子嵌套的不检查
if (row.array) {
return result;
}
// 可选的同时没有值不检查
if (row.optional === 'true' && !value) {
return result;
}
switch (type) {
case 'int':
if (filter && filter.indexOf('~') !== -1) {
const filterArr = filter.split('~');
const minInt = parseInt(filterArr[0]);
const maxInt = parseInt(filterArr[1]);
const valueInt = parseInt(value);
if (valueInt < minInt || valueInt > maxInt) {
return [
false,
t('views.configParam.configParamForm.requireInt', {
display,
filter,
}),
];
}
}
break;
case 'ipv4':
if (!regExpIPv4.test(value)) {
return [
false,
t('views.configParam.configParamForm.requireIpv4', { display }),
];
}
break;
case 'ipv6':
if (!regExpIPv6.test(value)) {
return [
false,
t('views.configParam.configParamForm.requireIpv6', { display }),
];
}
break;
case 'enum':
if (filter && filter.indexOf('{') === 1) {
let filterJson: Record<string, any> = {};
try {
filterJson = JSON.parse(filter); //string---json
} catch (error) {
console.error(error);
}
if (!Object.keys(filterJson).includes(`${value}`)) {
return [
false,
t('views.configParam.configParamForm.requireEnum', { display }),
];
}
}
break;
case 'bool':
if (filter && filter.indexOf('{') === 1) {
let filterJson: Record<string, any> = {};
try {
filterJson = JSON.parse(filter); //string---json
} catch (error) {
console.error(error);
}
if (!Object.values(filterJson).includes(`${value}`)) {
return [
false,
t('views.configParam.configParamForm.requireBool', { display }),
];
}
}
break;
case 'string':
if (filter && filter.indexOf('~') !== -1) {
try {
const filterArr = filter.split('~');
let rule = new RegExp(
'^\\S{' + filterArr[0] + ',' + filterArr[1] + '}$'
);
if (!rule.test(value)) {
return [
false,
t('views.configParam.configParamForm.requireString', { display }),
];
}
} catch (error) {
console.error(error);
}
}
break;
case 'regex':
if (filter) {
try {
let regex = new RegExp(filter);
if (!regex.test(value)) {
return [
false,
t('views.configParam.configParamForm.requireString', { display }),
];
}
} catch (error) {
console.error(error);
}
}
break;
default:
return [
false,
t('views.configParam.configParamForm.requireUn', { display }),
];
}
return result;
}
/**对话框对象信息状态类型 */
type ModalStateType = {
/**添加框是否显示 */
visibleByAdd: boolean;
/**标题 */
title: string;
/**表单数据 */
from: Record<string, any>;
/**确定按钮 loading */
confirmLoading: boolean;
/**项类型 */
type: 'array' | 'arrayChild';
/**项Key */
key: string | number;
/**项数据 */
data: Record<string, any>[];
};
/**对话框对象信息状态 */
let modalState: ModalStateType = reactive({
visibleByAdd: false,
title: 'Item',
from: {},
confirmLoading: false,
type: 'array',
key: '',
data: [],
});
/**
* 对话框弹出确认执行函数
* 进行表达规则校验
*/
function fnModalOk() {
const from = toRaw(modalState.from);
if (modalState.type === 'array') {
arrayAddOk(from);
}
if (modalState.type === 'arrayChild') {
arrayChildAddOk(from);
}
}
/**
* 对话框弹出关闭执行函数
* 进行表达规则校验
*/
function fnModalCancel() {
modalState.visibleByAdd = false;
modalState.from = {};
modalState.type = 'array';
modalState.key = '';
modalState.data = [];
}
onMounted(() => {
// 获取网元网元列表
useNeInfoStore()
.fnNelist()
.then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
if (res.data.length > 0) {
// 过滤不可用的网元
neCascaderOtions.value = useNeInfoStore().getNeCascaderOtions.filter(
(item: any) => {
return !['OMC'].includes(item.value);
}
);
// 默认选择AMF
const item = neCascaderOtions.value.find(s => s.value === 'UPF');
if (item) {
const info = item.children[0];
neTypeSelect.value = [info.neType, info.neId];
}
fnGetParamConfigTopTab();
}
} else {
message.warning({
content: t('common.noData'),
duration: 2,
});
}
});
});
</script>
<template>
<PageContainer>
<a-card
:bordered="false"
:body-style="{
marginBottom: '24px',
marginTop: '24px',
paddingBottom: 0,
}"
>
<!-- 表格搜索栏 -->
<a-form name="queryParams" layout="horizontal">
<a-row :gutter="16">
<a-col :lg="12" :md="12" :xs="24">
<a-form-item
:label="t('views.configManage.configParamForm.neType')"
name="neTypeSelect"
>
<a-cascader
v-model:value="neTypeSelect"
:options="neCascaderOtions"
:allow-clear="false"
@change="fnGetParamConfigTopTab"
/>
</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="fnGetParamConfigTopTab"
>
<template #icon><ReloadOutlined /></template>
{{ t('common.reloadText') }}
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false">
<a-tabs
destroy-inactive-tab-pane
v-model:activeKey="tabState.tabActiveTopTag"
:tab-position="tabState.tabPosition"
@change="fnTabActiveTopTag"
>
<a-tab-pane
v-for="tab in tabState.tabNames"
:key="tab.topTag"
:tab="tab.topDisplay"
>
<a-spin :spinning="tabState.loading">
<!-- 单列表格列表 -->
<a-table
v-if="tabState.tabType === 'list'"
class="table"
row-key="name"
:size="listState.size"
:columns="listState.columns"
:data-source="listState.data"
:pagination="false"
:bordered="true"
:scroll="{ x: true }"
>
<template #bodyCell="{ column, text, record }">
<template v-if="column.dataIndex === 'value'">
<a-tooltip placement="topLeft">
<template #title v-if="record.comment">
{{ record.comment }}
</template>
<div class="editable-cell">
<div
v-if="
listState.editRecord['display'] === record['display']
"
class="editable-cell__input-wrapper"
>
<a-input
v-if="
['string', 'ipv6', 'ipv4', 'regex'].includes(
record['type']
)
"
v-model:value="listState.editRecord['value']"
></a-input>
<a-input-number
v-else-if="record['type'] === 'int'"
v-model:value="listState.editRecord['value']"
:min="0"
:max="65535"
style="width: 100%"
></a-input-number>
<a-switch
v-else-if="record['type'] === 'bool'"
v-model:checked="listState.editRecord['value']"
:checked-children="t('common.switch.open')"
:un-checked-children="t('common.switch.shut')"
></a-switch>
<a-select
v-else-if="record['type'] === 'enum'"
v-model:value="listState.editRecord['value']"
:allow-clear="true"
style="width: 100%"
>
<a-select-option
:value="+v"
:key="+v"
v-for="(k, v) in JSON.parse(record['filter'])"
>
{{ k }}
</a-select-option>
</a-select>
<a-space
:size="16"
align="center"
direction="horizontal"
>
<a-tooltip placement="bottomRight">
<template #title> {{ t('common.ok') }} </template>
<a-popconfirm
:title="
t(
'views.configManage.configParamForm.editOkTip',
{ num: record['display'] }
)
"
placement="topRight"
@confirm="listEditOk()"
>
<a-button
type="text"
class="editable-cell__icon-edit"
>
<template #icon><CheckOutlined /></template>
</a-button>
</a-popconfirm>
</a-tooltip>
<a-tooltip placement="bottomRight">
<template #title>
{{ t('common.cancel') }}
</template>
<a-button
type="text"
class="editable-cell__icon-edit"
@click.prevent="listEditClose()"
>
<template #icon><CloseOutlined /></template>
</a-button>
</a-tooltip>
</a-space>
</div>
<div v-else class="editable-cell__text-wrapper">
<template v-if="record['type'] === 'enum'">
{{ JSON.parse(record['filter'])[text] }}
</template>
<template v-else>{{ `${text}` || '&nbsp;' }}</template>
<EditOutlined
class="editable-cell__icon"
v-if="record.access !== 'read'"
@click="listEdit(record)"
/>
</div>
</div>
</a-tooltip>
</template>
</template>
</a-table>
<!-- array类型 -->
<template v-if="tabState.tabType === 'array'">
<!-- 多列新增操作 -->
<a-button
type="primary"
@click.prevent="arrayAdd()"
v-if="tab.method !== 'get'"
>
<template #icon><PlusOutlined /></template>
{{ t('common.addText') }}
</a-button>
<a-collapse
collapsible="header"
v-model:activeKey="arrayState.collapseActiveKey"
>
<a-collapse-panel
:key="data.key"
:header="data.title"
v-for="data in arrayState.data"
>
<!-- 多列编辑操作 -->
<template #extra>
<a-space :size="16" v-if="tab.method !== 'get'">
<template
v-if="
arrayState.editKey === data.key &&
arrayState.newIndex === -1
"
>
<a-popconfirm
:title="
t(
'views.configManage.configParamForm.updateItemTip',
{ num: data.key }
)
"
placement="right"
@confirm="arrayEditOk()"
>
<a-button type="primary" size="small">
<template #icon><CheckOutlined /></template>
{{ t('common.ok') }}
</a-button>
</a-popconfirm>
<a-button
type="default"
size="small"
@click.prevent="arrayEditClose()"
>
<template #icon><CloseOutlined /></template>
{{ t('common.close') }}
</a-button>
</template>
<template
v-if="
arrayState.editKey !== data.key ||
arrayState.newIndex < -1
"
>
<a-button
type="default"
size="small"
@click.prevent="arrayEdit(data, -1)"
>
<template #icon><ProfileOutlined /></template>
{{ t('common.editText') }}
</a-button>
<a-popconfirm
:title="
t('views.configManage.configParamForm.delItemTip', {
num: data.key,
})
"
placement="topRight"
@confirm="arrayDelete(data)"
>
<a-button danger type="default" size="small">
<template #icon><DeleteOutlined /></template>
{{ t('common.deleteText') }}
</a-button>
</a-popconfirm>
</template>
</a-space>
</template>
<!-- 多列数据渲染 -->
<a-form
class="form"
layout="horizontal"
autocomplete="off"
:validate-on-rule-change="false"
:validateTrigger="[]"
>
<a-form-item
v-for="item in data.record"
:label="item.display"
:name="item.name"
:required="item.optional === 'false'"
>
<a-tooltip placement="topLeft">
<template #title v-if="item.comment">
{{ item.comment }}
</template>
<div>
<div
v-if="
!Array.isArray(item.array) &&
arrayState.editKey === data.key &&
arrayState.newIndex >= -1 &&
arrayState.editRecord[item.name] !== undefined
"
>
<a-input
v-if="
['string', 'ipv6', 'ipv4', 'regex'].includes(
item['type']
)
"
v-model:value="
arrayState.editRecord[item.name]['value']
"
:disabled="item.name === 'index'"
></a-input>
<a-input-number
v-else-if="item['type'] === 'int'"
v-model:value="
arrayState.editRecord[item.name]['value']
"
:min="0"
:max="65535"
:disabled="item.name === 'index'"
style="width: 100%"
></a-input-number>
<a-switch
v-else-if="item['type'] === 'bool'"
v-model:checked="
arrayState.editRecord[item.name]['value']
"
:checked-children="t('common.switch.open')"
:un-checked-children="t('common.switch.shut')"
></a-switch>
<a-select
v-else-if="item['type'] === 'enum'"
v-model:value="
arrayState.editRecord[item.name]['value']
"
:allow-clear="true"
style="width: 100%"
>
<a-select-option
:value="+v"
:key="+v"
v-for="(k, v) in JSON.parse(item['filter'])"
>
{{ k }}
</a-select-option>
</a-select>
</div>
<a-button
type="link"
size="small"
@click.prevent="arrayChildExpand(data.key, item)"
v-else-if="Array.isArray(item.array)"
>
{{
arrayState.newIndex === -1
? '-'
: t(
'views.configManage.configParamForm.arrayMore'
)
}}
</a-button>
<div v-else>
{{ `${item.value}` || '&nbsp;' }}
</div>
</div>
</a-tooltip>
<!-- 多列嵌套类型 -->
<template
#extra
v-if="
Array.isArray(item.array) &&
item.display === arrayChildState.title
"
>
<!-- 多列嵌套新增操作 -->
<a-space :size="16" v-if="tab.method !== 'get'">
<a-button
type="primary"
@click.prevent="arrayChildAdd()"
>
<template #icon><PlusOutlined /></template>
{{ t('common.addText') }}
</a-button>
<a-button
type="default"
@click.prevent="arrayChildExpandClose()"
>
<template #icon><CloseOutlined /></template>
{{ t('common.close') }}
</a-button>
</a-space>
<a-collapse
collapsible="header"
v-model:activeKey="arrayChildState.collapseActiveKey"
>
<a-collapse-panel
:key="cdata.key"
:header="cdata.title"
v-for="cdata in arrayChildState.data"
>
<!-- 多列嵌套编辑操作 -->
<template #extra>
<a-space :size="16" v-if="tab.method !== 'get'">
<template
v-if="
arrayChildState.editKey === cdata.key &&
arrayChildState.newIndex === -1
"
>
<a-popconfirm
:title="
t(
'views.configManage.configParamForm.updateItemTip',
{ num: cdata.key }
)
"
placement="right"
@confirm="arrayChildEditOk()"
>
<a-button type="primary" size="small">
<template #icon
><CheckOutlined
/></template>
{{ t('common.ok') }}
</a-button>
</a-popconfirm>
<a-button
type="default"
size="small"
@click.prevent="arrayChildEditClose()"
>
<template #icon><CloseOutlined /></template>
{{ t('common.close') }}
</a-button>
</template>
<template
v-if="
arrayChildState.editKey !== cdata.key ||
arrayChildState.newIndex < -1
"
>
<a-button
type="default"
size="small"
@click.prevent="arrayChildEdit(cdata, -1)"
>
<template #icon
><ProfileOutlined
/></template>
{{ t('common.editText') }}
</a-button>
<a-popconfirm
:title="
t(
'views.configManage.configParamForm.delItemTip',
{ num: cdata.key }
)
"
placement="topRight"
@confirm="arrayChildDelete(cdata)"
>
<a-button
danger
type="default"
size="small"
>
<template #icon>
<DeleteOutlined />
</template>
{{ t('common.deleteText') }}
</a-button>
</a-popconfirm>
</template>
</a-space>
</template>
<!-- 多列嵌套数据渲染 -->
<a-form
class="form"
layout="horizontal"
autocomplete="off"
:validate-on-rule-change="false"
:validateTrigger="[]"
>
<a-form-item
v-for="item in cdata.record"
:label="item.display"
:name="item.name"
:required="item.optional === 'false'"
>
<a-tooltip placement="topLeft">
<template #title v-if="item.comment">
{{ item.comment }}
</template>
<div>
<div
v-if="
!Array.isArray(item.array) &&
arrayChildState.newIndex >= -1 &&
arrayChildState.editKey === cdata.key &&
arrayChildState.editRecord[
item.name
] !== undefined
"
>
<a-input
v-if="
[
'string',
'ipv6',
'ipv4',
'regex',
].includes(item['type'])
"
v-model:value="
arrayChildState.editRecord[item.name][
'value'
]
"
:disabled="item.name === 'index'"
></a-input>
<a-input-number
v-else-if="item['type'] === 'int'"
v-model:value="
arrayChildState.editRecord[item.name][
'value'
]
"
:min="0"
:max="65535"
:disabled="item.name === 'index'"
style="width: 100%"
></a-input-number>
<a-switch
v-else-if="item['type'] === 'bool'"
v-model:checked="
arrayChildState.editRecord[item.name][
'value'
]
"
:checked-children="
t('common.switch.open')
"
:un-checked-children="
t('common.switch.shut')
"
></a-switch>
<a-select
v-else-if="item['type'] === 'enum'"
v-model:value="
arrayChildState.editRecord[item.name][
'value'
]
"
:allow-clear="true"
style="width: 100%"
>
<a-select-option
:value="+v"
:key="+v"
v-for="(k, v) in JSON.parse(
item['filter']
)"
>
{{ k }}
</a-select-option>
</a-select>
</div>
<a-button
type="link"
size="small"
v-else-if="Array.isArray(item.array)"
>
{{
arrayChildState.newIndex === -1
? '-'
: t(
'views.configManage.configParamForm.arrayMore'
)
}}
</a-button>
<div v-else>
{{ `${item.value || '&nbsp;'}` }}
</div>
</div>
</a-tooltip>
</a-form-item>
</a-form>
</a-collapse-panel>
</a-collapse>
</template>
</a-form-item>
</a-form>
</a-collapse-panel>
</a-collapse>
</template>
</a-spin>
</a-tab-pane>
</a-tabs>
</a-card>
<!-- 新增框或修改框 -->
<a-modal
width="800px"
:body-style="{ maxHeight: '650px', 'overflow-y': 'scroll' }"
:keyboard="false"
:mask-closable="false"
:visible="modalState.visibleByAdd"
:title="modalState.title"
:confirm-loading="modalState.confirmLoading"
@ok="fnModalOk"
@cancel="fnModalCancel"
>
<a-form
class="form"
layout="horizontal"
autocomplete="off"
:validate-on-rule-change="false"
:validateTrigger="[]"
>
<a-form-item
v-for="item in modalState.data"
:label="item.display"
:name="item.name"
:required="item.optional === 'false'"
>
<a-tooltip placement="topLeft">
<template #title v-if="item.comment">
{{ item.comment }}
</template>
<div>
<div
v-if="
!Array.isArray(item.array) &&
modalState.from[item.name] !== undefined
"
>
<a-input
v-if="
['string', 'ipv6', 'ipv4', 'regex'].includes(item['type'])
"
v-model:value="modalState.from[item.name]['value']"
:disabled="item.name === 'index'"
></a-input>
<a-input-number
v-else-if="item['type'] === 'int'"
v-model:value="modalState.from[item.name]['value']"
:min="0"
:max="65535"
:disabled="item.name === 'index'"
style="width: 100%"
></a-input-number>
<a-switch
v-else-if="item['type'] === 'bool'"
v-model:checked="modalState.from[item.name]['value']"
:checked-children="t('common.switch.open')"
:un-checked-children="t('common.switch.shut')"
></a-switch>
<a-select
v-else-if="item['type'] === 'enum'"
v-model:value="modalState.from[item.name]['value']"
:allow-clear="true"
style="width: 100%"
>
<a-select-option
:value="+v"
:key="+v"
v-for="(k, v) in JSON.parse(item['filter'])"
>
{{ k }}
</a-select-option>
</a-select>
</div>
<div v-else>
{{ `${item.value || '&nbsp;'}` }}
</div>
</div>
</a-tooltip>
</a-form-item>
</a-form>
</a-modal>
</PageContainer>
</template>
<style lang="less" scoped>
.editable-cell {
&__icon {
display: none;
cursor: pointer;
}
&__icon:hover {
color: var(--ant-primary-color);
}
&__icon-edit:hover {
color: var(--ant-primary-color);
}
&__text-wrapper {
font-size: 16px;
color: #333;
}
&__text-wrapper:hover &__icon {
display: inline-block;
}
&__input-wrapper {
display: flex;
justify-content: start;
align-items: center;
}
}
</style>