add psap version

This commit is contained in:
lai
2025-06-06 16:44:32 +08:00
parent af15418695
commit 270f9915dc
6 changed files with 486 additions and 308 deletions

View File

@@ -0,0 +1,16 @@
import { request } from '@/plugins/http-fetch';
/**
* 查询定时任务调度列表
* @param query 查询参数
* @returns object
*/
export function listCallBack(query: Record<string, any>) {
return request({
url: '/psap/v1/mf/ticket/list',
method: 'get',
params: query,
});
}

View File

@@ -358,6 +358,15 @@ export default {
answeredTime:'Answered Time',
callDuration:'Call Duration',
msdData:'MSD Info',
},
callback:{
callerIdNumber:'Caller Number',
calleeIdNumber:'Callee Number',
status:'Status',
ticketId:'Ticket ID',
startTime:'Start Time',
msdData:'MSD Info',
agentName: 'Agent Name',
}
},
dashboard: {

View File

@@ -358,6 +358,15 @@ export default {
answeredTime:'接听时间',
callDuration:'通话时长',
msdData:'MSD内容',
},
callback:{
callerIdNumber:'主叫号码',
calleeIdNumber:'被叫号码',
status:'状态',
ticketId:'工单编号',
startTime:'开始时间',
msdData:'MSD内容',
agentName: '座席名称',
}
},
dashboard: {

View File

@@ -0,0 +1,227 @@
<script setup lang="ts">
import { reactive, ref, onMounted, toRaw } from 'vue';
import { PageContainer } from 'antdv-pro-layout';
import { SizeType } from 'ant-design-vue/es/config-provider';
import { MenuInfo } from 'ant-design-vue/es/menu/src/interface';
import { ColumnsType } from 'ant-design-vue/es/table';
import { parseDateToStr,parseStrToDate } from '@/utils/date-utils';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { listCallBack } from '@/api/agentManage/callback';
import useNeInfoStore from '@/store/modules/neinfo';
import useDictStore from '@/store/modules/dict';
import useI18n from '@/hooks/useI18n';
const { getDict } = useDictStore();
const { t } = useI18n();
/**查询参数 */
let queryParams = reactive({
/**网元类型 */
neId: '001',
/**记录时间 */
beginTime: '',
endTime: '',
/**当前页数 */
pageNum: 1,
/**每页条数 */
pageSize: 20,
});
/**表格状态类型 */
type TabeStateType = {
/**加载等待 */
loading: boolean;
/**紧凑型 */
size: SizeType;
/**搜索栏 */
seached: boolean;
/**记录数据 */
data: object[];
};
/**表格状态 */
let tableState: TabeStateType = reactive({
loading: false,
size: 'middle',
seached: true,
data: [],
});
/**表格字段列 */
let tableColumns: ColumnsType = [
{
title: t('views.agentManage.callback.ticketId'),
dataIndex: 'ticketId',
align: 'center',
width: 5,
},
{
title: t('views.agentManage.callback.agentName'),
dataIndex: 'agentName',
align: 'center',
width: 5,
},
{
title: t('views.agentManage.callback.callerIdNumber'),
dataIndex: 'callerNumber',
align: 'center',
width: 5,
},
{
title: t('views.agentManage.callback.calleeIdNumber'),
dataIndex: 'calleeNumber',
align: 'center',
width: 5,
},
{
title: t('views.agentManage.callback.startTime'),
dataIndex: 'createdAt',
align: 'center',
width: 6,
customRender(opt) {
if (!opt.value) return '';
return parseDateToStr(opt.value/1000);
},
},
{
title: t('views.agentManage.callback.status'),
dataIndex: 'status',
align: 'center',
width: 4,
},
{
title: t('views.agentManage.callback.msdData'),
dataIndex: 'msdData',
align: 'center',
width: 6,
},
];
/**表格分页器参数 */
let tablePagination = reactive({
/**当前页数 */
current: 1,
/**每页条数 */
pageSize: 20,
/**默认的每页条数 */
defaultPageSize: 20,
/**指定每页可以显示多少条 */
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;
queryParams.pageNum = page;
queryParams.pageSize = pageSize;
fnGetList();
},
});
/**表格紧凑型变更操作 */
function fnTableSize({ key }: MenuInfo) {
tableState.size = key as SizeType;
}
/**查询备份信息列表, pageNum初始页数 */
function fnGetList(pageNum?: number) {
if (tableState.loading) return;
tableState.loading = true;
if (pageNum) {
queryParams.pageNum = pageNum;
}
listCallBack(toRaw(queryParams)).then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
tablePagination.total = res.total;
tableState.data = res.data;
if (tablePagination.total <= (queryParams.pageNum - 1) * tablePagination.pageSize && queryParams.pageNum !== 1) {
tableState.loading = false;
fnGetList(queryParams.pageNum - 1);
}
}
tableState.loading = false;
});
}
onMounted(() => {
// 获取列表数据
fnGetList();
});
</script>
<template>
<PageContainer>
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title> </template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<a-tooltip>
<template #title>{{ t('common.reloadText') }}</template>
<a-button type="text" @click.prevent="fnGetList()">
<template #icon>
<ReloadOutlined />
</template>
</a-button>
</a-tooltip>
<a-tooltip>
<template #title>{{ t('common.sizeText') }}</template>
<a-dropdown trigger="click" placement="bottomRight">
<a-button type="text">
<template #icon>
<ColumnHeightOutlined />
</template>
</a-button>
<template #overlay>
<a-menu :selected-keys="[tableState.size as string]" @click="fnTableSize">
<a-menu-item key="default">
{{ t('common.size.default') }}
</a-menu-item>
<a-menu-item key="middle">
{{ t('common.size.middle') }}
</a-menu-item>
<a-menu-item key="small">
{{ t('common.size.small') }}
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</a-tooltip>
</a-space>
</template>
<!-- 表格列表 -->
<a-table class="table" row-key="id" :columns="tableColumns" :loading="tableState.loading"
:data-source="tableState.data" :size="tableState.size" :pagination="tablePagination"
:scroll="{ x: 1500, y: 400 }">
</a-table>
</a-card>
</PageContainer>
</template>
<style lang="less" scoped>
.table :deep(.ant-pagination) {
padding: 0 24px;
}
.alarmTitleText {
max-width: 300px;
cursor: pointer;
}
</style>

View File

@@ -54,7 +54,7 @@ function updateChartData(newValue: number, dataArray: any) {
const isFirstLoadUser = ref(true);
function updateUserChartData(newValue: number, dataArray: any) {
// 如果是第一次加载,用当前值填充整个数组
if (isFirstLoad.value) {
if (isFirstLoadUser.value) {
dataArray.value = Array(7).fill(newValue);
} else {
// 非第一次加载,正常更新数据(移除第一个,添加新值)
@@ -272,7 +272,6 @@ function fnGetList() {
prevFailedCallsCount.value = failedCallsCount.value;
// 更新 activeCallsData 和 mosData
failedCallsCount.value = res.total; // 数组长度
failedCallsCountChange.value = prevFailedCallsCount.value ? prevFailedCallsCount.value - failedCallsCount.value : 0;
@@ -323,7 +322,7 @@ onBeforeUnmount(() => {
<div class="row-title">{{ t('views.dashboard.overview.userTitle') }}</div>
<a-row :gutter="[48, 48]">
<a-col :xs="24" :sm="24" :lg="8">
<a-card :bordered="false" class="metric-card">
<a-card :bordered="false" class="metric-card" @click="fnToRouter('NeConfig_2146',{neType:'MF',treeName:'agents'})">
<div class="card-title">{{ t('views.dashboard.overview.totalUser') }}</div>
<div class="card-content">
<div class="trend-chart">
@@ -342,7 +341,7 @@ onBeforeUnmount(() => {
</a-col>
<a-col :xs="24" :sm="24" :lg="8">
<a-card :bordered="false" class="metric-card">
<a-card :bordered="false" class="metric-card" @click="fnToRouter('NeConfig_2146',{neType:'MF',treeName:'agents'})">
<div class="card-title">{{ t('views.dashboard.overview.onlineUser') }}</div>
<div class="card-content">
<div class="trend-chart">

View File

@@ -13,6 +13,9 @@ import useConfigList from './hooks/useConfigList';
import useConfigArray from './hooks/useConfigArray';
import useConfigArrayChild from './hooks/useConfigArrayChild';
import { getAllNeConfig, getNeConfigData } from '@/api/ne/neConfig';
import { useRoute } from 'vue-router';
const route = useRoute();
const neInfoStore = useNeInfoStore();
const { t } = useI18n();
const { ruleVerification, smfByUPFIdLoadData, smfByUPFIdOptions } = useOptions({
@@ -76,6 +79,7 @@ function fnSelectConfigNode(_: any, info: any) {
if (treeState.selectNode.paramName == key) {
return;
}
fnActiveConfigNode(key);
}
@@ -168,15 +172,44 @@ function fnActiveConfigNode(key: string | number) {
// 列表字段
const columns: Record<string, any>[] = [];
for (const rule of arrayState.dataRule.record) {
columns.push({
title: rule.display,
dataIndex: rule.name,
align: 'left',
resizable: true,
width: 150,
minWidth: 100,
maxWidth: 350,
});
if (rule.name === 'name') {
columns.push({
title: rule.display,
dataIndex: rule.name,
align: 'left',
resizable: true,
width: 150,
minWidth: 100,
maxWidth: 350,
customFilterDropdown: true,
onFilter: (value: any, record: any) => {
const regex = new RegExp('^[0-9]{4,8}$');
const name = record.name.value?.toString().trim() || '';
const filterValue = value?.toString().trim();
return regex.test(name) && name.includes(filterValue); // 正则匹配且模糊查询
},
onFilterDropdownOpenChange: (visible: any) => {
if (visible) {
setTimeout(() => {
searchInput.value.focus();
}, 100);
}
},
});
} else {
columns.push({
title: rule.display,
dataIndex: rule.name,
align: 'left',
resizable: true,
width: 150,
minWidth: 100,
maxWidth: 350,
});
}
}
columns.push({
title: t('common.operate'),
@@ -203,7 +236,7 @@ function fnActiveConfigNode(key: string | number) {
}
/**查询配置可选属性值列表 */
function fnGetNeConfig() {
function fnGetNeConfig(routeSelect?: string) {
const neType = neTypeSelect.value[0];
if (!neType) {
message.warning({
@@ -240,7 +273,8 @@ function fnGetNeConfig() {
const item = JSON.parse(JSON.stringify(treeState.data[0]));
treeState.selectNode = item;
treeState.selectLoading = false;
fnActiveConfigNode(item.key);
// fnActiveConfigNode(((route.query.treeName as string)||item.key));
fnActiveConfigNode(routeSelect || item.key);
}
}
});
@@ -362,6 +396,25 @@ const {
arrayEditClose,
});
const state = reactive({
searchText: '',
searchedColumn: '',
});
const searchInput = ref();
const handleSearch = (selectedKeys: any, confirm: any, dataIndex: any) => {
confirm();
state.searchText = selectedKeys[0];
state.searchedColumn = dataIndex;
};
const handleReset = (clearFilters: any) => {
clearFilters({ confirm: true });
state.searchText = '';
};
onMounted(() => {
// 获取网元网元列表
neInfoStore.fnNelist().then(res => {
@@ -381,7 +434,7 @@ onMounted(() => {
return;
}
// 默认选择AMF
const item = neCascaderOptions.value.find(s => s.value === 'AMF');
const item = neCascaderOptions.value.find(s => s.value === ((route.query.neType as string) || 'MF'));
if (item && item.children) {
const info = item.children[0];
neTypeSelect.value = [info.neType, info.neId];
@@ -389,7 +442,7 @@ onMounted(() => {
const info = neCascaderOptions.value[0].children[0];
neTypeSelect.value = [info.neType, info.neId];
}
fnGetNeConfig();
fnGetNeConfig((route.query.treeName as string));
}
} else {
message.warning({
@@ -404,13 +457,7 @@ onMounted(() => {
<template>
<PageContainer>
<a-row :gutter="16">
<a-col
:lg="6"
:md="6"
:xs="24"
style="margin-bottom: 24px"
v-show="collapsible"
>
<a-col :lg="6" :md="6" :xs="24" style="margin-bottom: 24px" v-show="collapsible">
<!-- 网元类型 -->
<a-card size="small" :bordered="false" :loading="treeState.loading">
<template #title>
@@ -418,37 +465,22 @@ onMounted(() => {
</template>
<a-form layout="vertical" autocomplete="off">
<a-form-item name="neId ">
<a-cascader
v-model:value="neTypeSelect"
:options="neCascaderOptions"
:allow-clear="false"
@change="fnGetNeConfig"
/>
<a-cascader v-model:value="neTypeSelect" :options="neCascaderOptions" :allow-clear="false"
@change="fnGetNeConfig()" />
</a-form-item>
<a-form-item name="treeStateData">
<a-tree
:tree-data="treeState.data"
:selected-keys="[treeState.selectNode.paramName]"
@select="fnSelectConfigNode"
>
<a-tree :tree-data="treeState.data" :selected-keys="[treeState.selectNode.paramName]"
@select="fnSelectConfigNode">
</a-tree>
</a-form-item>
</a-form>
</a-card>
</a-col>
<a-col :lg="collapsible ? 18 : 24" :md="collapsible ? 18 : 24" :xs="24">
<a-card
size="small"
:bordered="false"
:body-style="{ maxHeight: '600px', 'overflow-y': 'auto' }"
:loading="treeState.selectLoading"
>
<a-card size="small" :bordered="false" :body-style="{ maxHeight: '600px', 'overflow-y': 'auto' }"
:loading="treeState.selectLoading">
<template #title>
<a-button
type="text"
size="small"
@click.prevent="changeCollapsible()"
>
<a-button type="text" size="small" @click.prevent="changeCollapsible()">
<template #icon>
<MenuFoldOutlined v-show="collapsible" />
<MenuUnfoldOutlined v-show="!collapsible" />
@@ -466,11 +498,7 @@ onMounted(() => {
<a-space :size="8" align="center" v-show="!treeState.selectLoading">
<a-tooltip placement="topRight">
<template #title>{{ t('common.reloadText') }}</template>
<a-button
type="default"
size="small"
@click.prevent="fnActiveConfigNode('#')"
>
<a-button type="default" size="small" @click.prevent="fnActiveConfigNode('#')">
<template #icon>
<ReloadOutlined />
</template>
@@ -480,17 +508,9 @@ onMounted(() => {
</template>
<!-- 单列表格列表 -->
<a-table
v-if="treeState.selectNode.paramType === 'list'"
class="table"
row-key="name"
:size="listState.size"
:columns="listState.columns"
:data-source="listState.data"
:pagination="tablePagination"
:bordered="true"
:scroll="{ x: true, y: '500px' }"
>
<a-table v-if="treeState.selectNode.paramType === 'list'" class="table" row-key="name" :size="listState.size"
:columns="listState.columns" :data-source="listState.data" :pagination="tablePagination" :bordered="true"
:scroll="{ x: true, y: '500px' }">
<template #bodyCell="{ column, text, record }">
<template v-if="column.dataIndex === 'value'">
<a-tooltip placement="topLeft">
@@ -498,68 +518,30 @@ onMounted(() => {
{{ record.comment }}
</template>
<div class="editable-cell">
<div
v-if="
listState.editRecord['display'] === record['display']
"
class="editable-cell__input-wrapper"
>
<a-input-number
v-if="record['type'] === 'int'"
v-model:value="listState.editRecord['value']"
:disabled="listState.confirmLoading"
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')"
:disabled="listState.confirmLoading"
></a-switch>
<a-select
v-else-if="record['type'] === 'enum'"
v-model:value="listState.editRecord['value']"
:allow-clear="true"
:disabled="listState.confirmLoading"
style="width: 100%"
>
<a-select-option
:value="+v"
:key="+v"
v-for="(k, v) in JSON.parse(record['filter'])"
>
<div v-if="
listState.editRecord['display'] === record['display']
" class="editable-cell__input-wrapper">
<a-input-number v-if="record['type'] === 'int'" v-model:value="listState.editRecord['value']"
:disabled="listState.confirmLoading" 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')"
:disabled="listState.confirmLoading"></a-switch>
<a-select v-else-if="record['type'] === 'enum'" v-model:value="listState.editRecord['value']"
:allow-clear="true" :disabled="listState.confirmLoading" 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-input
v-else
v-model:value="listState.editRecord['value']"
:disabled="listState.confirmLoading"
></a-input>
<a-space
:size="8"
align="center"
direction="horizontal"
style="margin-left: 18px"
>
<a-input v-else v-model:value="listState.editRecord['value']"
:disabled="listState.confirmLoading"></a-input>
<a-space :size="8" align="center" direction="horizontal" style="margin-left: 18px">
<a-tooltip placement="bottomRight">
<template #title> {{ t('common.ok') }} </template>
<a-popconfirm
:title="
t('views.ne.neConfig.editOkTip', {
num: record['display'],
})
"
placement="topRight"
:disabled="listState.confirmLoading"
@confirm="listEditOk()"
>
<a-button
type="text"
class="editable-cell__icon-edit"
:disabled="listState.confirmLoading"
>
<a-popconfirm :title="t('views.ne.neConfig.editOkTip', {
num: record['display'],
})
" placement="topRight" :disabled="listState.confirmLoading" @confirm="listEditOk()">
<a-button type="text" class="editable-cell__icon-edit" :disabled="listState.confirmLoading">
<template #icon>
<CheckOutlined />
</template>
@@ -568,12 +550,8 @@ onMounted(() => {
</a-tooltip>
<a-tooltip placement="bottomRight">
<template #title> {{ t('common.cancel') }} </template>
<a-button
type="text"
class="editable-cell__icon-edit"
:disabled="listState.confirmLoading"
@click.prevent="listEditClose()"
>
<a-button type="text" class="editable-cell__icon-edit" :disabled="listState.confirmLoading"
@click.prevent="listEditClose()">
<template #icon>
<CloseOutlined />
</template>
@@ -581,24 +559,16 @@ onMounted(() => {
</a-tooltip>
</a-space>
</div>
<div
v-else
class="editable-cell__text-wrapper"
@dblclick="listEdit(record)"
>
<div v-else class="editable-cell__text-wrapper" @dblclick="listEdit(record)">
<template v-if="record['type'] === 'enum'">
{{ JSON.parse(record['filter'])[text] || '&nbsp;' }}
</template>
<template v-else>{{ `${text}` || '&nbsp;' }}</template>
<EditOutlined
class="editable-cell__icon"
@click="listEdit(record)"
style="margin-left: 18px"
<EditOutlined class="editable-cell__icon" @click="listEdit(record)" style="margin-left: 18px"
v-if="
!listState.confirmLoading &&
!['read-only', 'read', 'ro'].includes(record.access)
"
/>
" />
</div>
</div>
</a-tooltip>
@@ -608,65 +578,77 @@ onMounted(() => {
<!-- array类型 -->
<template v-else-if="treeState.selectNode.paramType === 'array'">
<a-table
class="table"
row-key="index"
:columns="treeState.selectNode.paramPerms.includes('get') ? arrayState.columnsDnd.filter((s:any)=>s.key !== 'index') : arrayState.columnsDnd"
:data-source="arrayState.columnsData"
:size="arrayState.size"
:pagination="tablePagination"
:bordered="true"
:scroll="{ x: arrayState.columnsDnd.length * 200, y: 480 }"
@resizeColumn="(w:number, col:any) => (col.width = w)"
:show-expand-column="false"
v-model:expanded-row-keys="arrayState.arrayChildExpandKeys"
>
<a-table class="table" row-key="index"
:columns="treeState.selectNode.paramPerms.includes('get') ? arrayState.columnsDnd.filter((s: any) => s.key !== 'index') : arrayState.columnsDnd"
:data-source="arrayState.columnsData" :size="arrayState.size" :pagination="tablePagination"
:bordered="true" :scroll="{ x: arrayState.columnsDnd.length * 200, y: 480 }"
@resizeColumn="(w: number, col: any) => (col.width = w)" :show-expand-column="false"
v-model:expanded-row-keys="arrayState.arrayChildExpandKeys">
<!-- 多列新增操作 -->
<template #title>
<a-space :size="16" align="center">
<a-button
type="primary"
@click.prevent="arrayAdd()"
size="small"
v-if="treeState.selectNode.paramPerms.includes('post')"
>
<template #icon> <PlusOutlined /> </template>
<a-button type="primary" @click.prevent="arrayAdd()" size="small"
v-if="treeState.selectNode.paramPerms.includes('post')">
<template #icon>
<PlusOutlined />
</template>
{{ t('common.addText') }}
</a-button>
<TableColumnsDnd
type="ghost"
:cache-id="treeState.selectNode.key"
:columns="treeState.selectNode.paramPerms.includes('get') ? [...arrayState.columns.filter((s:any)=>s.key !== 'index')] : arrayState.columns"
v-model:columns-dnd="arrayState.columnsDnd"
></TableColumnsDnd>
<TableColumnsDnd type="ghost" :cache-id="treeState.selectNode.key"
:columns="treeState.selectNode.paramPerms.includes('get') ? [...arrayState.columns.filter((s: any) => s.key !== 'index')] : arrayState.columns"
v-model:columns-dnd="arrayState.columnsDnd"></TableColumnsDnd>
</a-space>
</template>
<template #customFilterDropdown="{ setSelectedKeys, selectedKeys, confirm, clearFilters, column }">
<div style="padding: 8px">
<a-input ref="searchInput" :placeholder="`Search ${column.dataIndex}`" :value="selectedKeys[0]"
style="width: 188px; margin-bottom: 8px; display: block"
@change="e => setSelectedKeys(e.target.value ? [e.target.value] : [])"
@pressEnter="handleSearch(selectedKeys, confirm, column.dataIndex)" />
<a-button type="primary" size="small" style="width: 90px; margin-right: 8px"
@click="handleSearch(selectedKeys, confirm, column.dataIndex)">
<template #icon>
<SearchOutlined />
</template>
Search
</a-button>
<a-button size="small" style="width: 90px" @click="handleReset(clearFilters)">
Reset
</a-button>
</div>
</template>
<template #customFilterIcon="{ filtered }">
<search-outlined :style="{ color: filtered ? '#108ee9' : undefined }" />
</template>
<!-- 多列数据渲染 -->
<template #bodyCell="{ column, text, record }">
<template v-if="column?.key === 'index'">
<a-space :size="16" align="center">
<a-tooltip
v-if="treeState.selectNode.paramPerms.includes('put')"
>
<a-tooltip v-if="treeState.selectNode.paramPerms.includes('put')">
<template #title>{{ t('common.editText') }}</template>
<a-button type="link" @click.prevent="arrayEdit(text)">
<template #icon><FormOutlined /></template>
<template #icon>
<FormOutlined />
</template>
</a-button>
</a-tooltip>
<a-tooltip
v-if="
treeState.selectNode.paramPerms.includes('delete') &&
!(
neTypeSelect[0] === 'IMS' &&
treeState.selectNode.paramName === 'plmn' &&
text['value'] === 0
)
"
>
<a-tooltip v-if="
treeState.selectNode.paramPerms.includes('delete') &&
!(
neTypeSelect[0] === 'IMS' &&
treeState.selectNode.paramName === 'plmn' &&
text['value'] === 0
)
">
<template #title>{{ t('common.deleteText') }}</template>
<a-button type="link" @click.prevent="arrayDelete(text)">
<template #icon><DeleteOutlined /></template>
<template #icon>
<DeleteOutlined />
</template>
</a-button>
</a-tooltip>
</a-space>
@@ -678,28 +660,24 @@ onMounted(() => {
</template>
<div class="editable-cell">
<template v-if="text.array">
<a-button
type="default"
size="small"
@click.prevent="
arrayChildExpand(record['index'], text)
"
>
<template #icon><BarsOutlined /></template>
<a-button type="default" size="small" @click.prevent="
arrayChildExpand(record['index'], text)
">
<template #icon>
<BarsOutlined />
</template>
{{ t('views.ne.neConfig.arrayMore') }}
</a-button>
<!--特殊字段拓展显示-->
<span
v-if="
text.name === 'dnnList' && Array.isArray(text.value)
"
>
<span v-if="
text.name === 'dnnList' && Array.isArray(text.value)
">
({{
text.value.length > 4
? `${text.value
.slice(0, 3)
.map((s: any) => s.dnn)
.join()}...${text.value.length}`
.slice(0, 3)
.map((s: any) => s.dnn)
.join()}...${text.value.length}`
: text.value.map((s: any) => s.dnn).join()
}})
</span>
@@ -720,37 +698,23 @@ onMounted(() => {
<!-- 多列嵌套类型 -->
<template #expandedRowRender>
<a-table
class="table"
row-key="index"
:columns="arrayChildState.columnsDnd"
:data-source="arrayChildState.columnsData"
:size="arrayChildState.size"
:pagination="tablePagination"
:bordered="true"
:scroll="{
<a-table class="table" row-key="index" :columns="arrayChildState.columnsDnd"
:data-source="arrayChildState.columnsData" :size="arrayChildState.size" :pagination="tablePagination"
:bordered="true" :scroll="{
x: arrayChildState.columnsDnd.length * 200,
y: 200,
}"
@resizeColumn="(w:number, col:any) => (col.width = w)"
>
}" @resizeColumn="(w: number, col: any) => (col.width = w)">
<template #title>
<a-space :size="16" align="center">
<a-button
type="primary"
@click.prevent="arrayChildAdd"
size="small"
>
<template #icon> <PlusOutlined /> </template>
<a-button type="primary" @click.prevent="arrayChildAdd" size="small">
<template #icon>
<PlusOutlined />
</template>
{{ t('common.addText') }} {{ arrayChildState.title }}
</a-button>
<TableColumnsDnd
type="ghost"
:cache-id="`${treeState.selectNode.key}:${arrayChildState.loc}`"
:columns="[...arrayChildState.columns]"
v-model:columns-dnd="arrayChildState.columnsDnd"
v-if="arrayChildState.loc"
></TableColumnsDnd>
<TableColumnsDnd type="ghost" :cache-id="`${treeState.selectNode.key}:${arrayChildState.loc}`"
:columns="[...arrayChildState.columns]" v-model:columns-dnd="arrayChildState.columnsDnd"
v-if="arrayChildState.loc"></TableColumnsDnd>
</a-space>
</template>
<template #bodyCell="{ column, text, record }">
@@ -758,22 +722,20 @@ onMounted(() => {
<a-space :size="8" align="center">
<a-tooltip>
<template #title>{{ t('common.editText') }}</template>
<a-button
type="link"
@click.prevent="arrayChildEdit(text)"
>
<template #icon><FormOutlined /></template>
<a-button type="link" @click.prevent="arrayChildEdit(text)">
<template #icon>
<FormOutlined />
</template>
</a-button>
</a-tooltip>
<a-tooltip>
<template #title>
{{ t('common.deleteText') }}
</template>
<a-button
type="link"
@click.prevent="arrayChildDelete(text)"
>
<template #icon><DeleteOutlined /></template>
<a-button type="link" @click.prevent="arrayChildDelete(text)">
<template #icon>
<DeleteOutlined />
</template>
</a-button>
</a-tooltip>
</a-space>
@@ -786,7 +748,9 @@ onMounted(() => {
<div class="editable-cell">
<template v-if="text.array">
<a-button type="default" size="small">
<template #icon><BarsOutlined /></template>
<template #icon>
<BarsOutlined />
</template>
{{ t('views.ne.neConfig.arrayMore') }}
</a-button>
</template>
@@ -816,97 +780,46 @@ onMounted(() => {
</a-row>
<!-- 新增框或修改框 -->
<ProModal
:drag="true"
:width="800"
:destroyOnClose="true"
:body-style="{ maxHeight: '600px', 'overflow-y': 'auto' }"
:keyboard="false"
:mask-closable="false"
:open="modalState.open"
: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="[]"
:label-col="{ span: 6 }"
:labelWrap="true"
>
<a-form-item
v-for="item in modalState.data"
:label="item.display"
:name="item.name"
:required="item.optional === 'false'"
style="margin-bottom: 4px"
>
<ProModal :drag="true" :width="800" :destroyOnClose="true"
:body-style="{ maxHeight: '600px', 'overflow-y': 'auto' }" :keyboard="false" :mask-closable="false"
:open="modalState.open" :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="[]"
:label-col="{ span: 6 }" :labelWrap="true">
<a-form-item v-for="item in modalState.data" :label="item.display" :name="item.name"
:required="item.optional === 'false'" style="margin-bottom: 4px">
<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
"
>
<div v-if="
!Array.isArray(item.array) &&
modalState.from[item.name] !== undefined
">
<!-- 特殊SMF-upfid选择 -->
<a-select
v-if="
neTypeSelect[0] === 'SMF' &&
modalState.from[item.name]['name'] === 'upfId'
"
v-model:value="modalState.from[item.name]['value']"
:options="smfByUPFIdOptions"
:disabled="['read-only', 'read', 'ro'].includes(item.access)"
:token-separators="[',', ';']"
mode="multiple"
:max-tag-count="5"
:allow-clear="true"
style="width: 100%"
>
<a-select v-if="
neTypeSelect[0] === 'SMF' &&
modalState.from[item.name]['name'] === 'upfId'
" v-model:value="modalState.from[item.name]['value']" :options="smfByUPFIdOptions"
:disabled="['read-only', 'read', 'ro'].includes(item.access)" :token-separators="[',', ';']"
mode="multiple" :max-tag-count="5" :allow-clear="true" style="width: 100%">
</a-select>
<!-- 常规 -->
<a-input-number
v-else-if="item['type'] === 'int'"
v-model:value="modalState.from[item.name]['value']"
:disabled="['read-only', 'read', 'ro'].includes(item.access)"
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')"
:disabled="['read-only', 'read', 'ro'].includes(item.access)"
></a-switch>
<a-select
v-else-if="item['type'] === 'enum'"
v-model:value="modalState.from[item.name]['value']"
:disabled="['read-only', 'read', 'ro'].includes(item.access)"
:allow-clear="true"
style="width: 100%"
>
<a-select-option
:value="+v"
:key="+v"
v-for="(k, v) in JSON.parse(item['filter'])"
>
<a-input-number v-else-if="item['type'] === 'int'" v-model:value="modalState.from[item.name]['value']"
:disabled="['read-only', 'read', 'ro'].includes(item.access)" 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')"
:disabled="['read-only', 'read', 'ro'].includes(item.access)"></a-switch>
<a-select v-else-if="item['type'] === 'enum'" v-model:value="modalState.from[item.name]['value']"
:disabled="['read-only', 'read', 'ro'].includes(item.access)" :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>
<a-input
v-else
v-model:value="modalState.from[item.name]['value']"
:disabled="['read-only', 'read', 'ro'].includes(item.access)"
></a-input>
<a-input v-else v-model:value="modalState.from[item.name]['value']"
:disabled="['read-only', 'read', 'ro'].includes(item.access)"></a-input>
</div>
<div v-else>
{{ `${item.value || '&nbsp;'}` }}
@@ -925,19 +838,24 @@ onMounted(() => {
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: inherit;
}
&__text-wrapper:hover &__icon {
display: inline-block;
}
&__input-wrapper {
display: flex;
justify-content: start;