feat(运维管理): 调整系统配置,添加运维管理相关页面
- 关闭tab标签、前端更新检测(后期正式环境开启回来) - 添加网络组件、协议管理、设备接入网关页面(未完成)和对接接口
This commit is contained in:
parent
f53bed6616
commit
fe3c9b570e
|
@ -0,0 +1,61 @@
|
|||
import type { GatewayVO, GatewayForm, GatewayQuery } from './model';
|
||||
|
||||
import type { ID, IDS } from '#/api/common';
|
||||
import type { PageResult } from '#/api/common';
|
||||
|
||||
import { commonExport } from '#/api/helper';
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
/**
|
||||
* 查询设备接入网关列表
|
||||
* @param params
|
||||
* @returns 设备接入网关列表
|
||||
*/
|
||||
export function gatewayList(params?: GatewayQuery) {
|
||||
return requestClient.get<PageResult<GatewayVO>>('/operations/gateway/list', { params });
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出设备接入网关列表
|
||||
* @param params
|
||||
* @returns 设备接入网关列表
|
||||
*/
|
||||
export function gatewayExport(params?: GatewayQuery) {
|
||||
return commonExport('/operations/gateway/export', params ?? {});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询设备接入网关详情
|
||||
* @param id id
|
||||
* @returns 设备接入网关详情
|
||||
*/
|
||||
export function gatewayInfo(id: ID) {
|
||||
return requestClient.get<GatewayVO>(`/operations/gateway/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增设备接入网关
|
||||
* @param data
|
||||
* @returns void
|
||||
*/
|
||||
export function gatewayAdd(data: GatewayForm) {
|
||||
return requestClient.postWithMsg<void>('/operations/gateway', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新设备接入网关
|
||||
* @param data
|
||||
* @returns void
|
||||
*/
|
||||
export function gatewayUpdate(data: GatewayForm) {
|
||||
return requestClient.putWithMsg<void>('/operations/gateway', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除设备接入网关
|
||||
* @param id id
|
||||
* @returns void
|
||||
*/
|
||||
export function gatewayRemove(id: ID | IDS) {
|
||||
return requestClient.deleteWithMsg<void>(`/operations/gateway/${id}`);
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
import type { PageQuery, BaseEntity } from '#/api/common';
|
||||
|
||||
export interface GatewayVO {
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 启用状态 0 禁用
|
||||
*/
|
||||
enabled: string;
|
||||
|
||||
/**
|
||||
* 网关名称
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* 接入方式,如: mqtt-server-gateway
|
||||
*/
|
||||
provider: string | number;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
description: string;
|
||||
|
||||
/**
|
||||
* 通道 接入通道(方式),如网络组件
|
||||
*/
|
||||
channel: string;
|
||||
|
||||
/**
|
||||
* 通道id 接入使用的通道ID,如: 网络组件ID,modbus通道ID
|
||||
*/
|
||||
channelId: string | number;
|
||||
|
||||
/**
|
||||
* 消息协议 消息协议
|
||||
*/
|
||||
protocol: number;
|
||||
|
||||
/**
|
||||
* 传输协议,如TCP,MQTT,UDP
|
||||
*/
|
||||
transport: string;
|
||||
|
||||
/**
|
||||
* 网关配置
|
||||
*/
|
||||
gatewayConfig: string;
|
||||
|
||||
}
|
||||
|
||||
export interface GatewayForm extends BaseEntity {
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 启用状态 0 禁用
|
||||
*/
|
||||
enabled?: string;
|
||||
|
||||
/**
|
||||
* 网关名称
|
||||
*/
|
||||
name?: string;
|
||||
|
||||
/**
|
||||
* 接入方式,如: mqtt-server-gateway
|
||||
*/
|
||||
provider?: string | number;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* 通道 接入通道(方式),如网络组件
|
||||
*/
|
||||
channel?: string;
|
||||
|
||||
/**
|
||||
* 通道id 接入使用的通道ID,如: 网络组件ID,modbus通道ID
|
||||
*/
|
||||
channelId?: string | number;
|
||||
|
||||
/**
|
||||
* 消息协议 消息协议
|
||||
*/
|
||||
protocol?: number;
|
||||
|
||||
/**
|
||||
* 传输协议,如TCP,MQTT,UDP
|
||||
*/
|
||||
transport?: string;
|
||||
|
||||
/**
|
||||
* 网关配置
|
||||
*/
|
||||
gatewayConfig?: string;
|
||||
|
||||
}
|
||||
|
||||
export interface GatewayQuery extends PageQuery {
|
||||
/**
|
||||
* 启用状态 0 禁用
|
||||
*/
|
||||
enabled?: string;
|
||||
|
||||
/**
|
||||
* 网关名称
|
||||
*/
|
||||
name?: string;
|
||||
|
||||
/**
|
||||
* 接入方式,如: mqtt-server-gateway
|
||||
*/
|
||||
provider?: string | number;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* 通道 接入通道(方式),如网络组件
|
||||
*/
|
||||
channel?: string;
|
||||
|
||||
/**
|
||||
* 通道id 接入使用的通道ID,如: 网络组件ID,modbus通道ID
|
||||
*/
|
||||
channelId?: string | number;
|
||||
|
||||
/**
|
||||
* 消息协议 消息协议
|
||||
*/
|
||||
protocol?: number;
|
||||
|
||||
/**
|
||||
* 传输协议,如TCP,MQTT,UDP
|
||||
*/
|
||||
transport?: string;
|
||||
|
||||
/**
|
||||
* 网关配置
|
||||
*/
|
||||
gatewayConfig?: string;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
import type { NetworkVO, NetworkForm, NetworkQuery } from './model';
|
||||
|
||||
import type { ID, IDS } from '#/api/common';
|
||||
import type { PageResult } from '#/api/common';
|
||||
|
||||
import { commonExport } from '#/api/helper';
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
/**
|
||||
* 查询网络组件列表
|
||||
* @param params
|
||||
* @returns 网络组件列表
|
||||
*/
|
||||
export function networkList(params?: NetworkQuery) {
|
||||
return requestClient.get<PageResult<NetworkVO>>('/operations/network/list', { params });
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出网络组件列表
|
||||
* @param params
|
||||
* @returns 网络组件列表
|
||||
*/
|
||||
export function networkExport(params?: NetworkQuery) {
|
||||
return commonExport('/operations/network/export', params ?? {});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询网络组件详情
|
||||
* @param id id
|
||||
* @returns 网络组件详情
|
||||
*/
|
||||
export function networkInfo(id: ID) {
|
||||
return requestClient.get<NetworkVO>(`/operations/network/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增网络组件
|
||||
* @param data
|
||||
* @returns void
|
||||
*/
|
||||
export function networkAdd(data: NetworkForm) {
|
||||
return requestClient.postWithMsg<void>('/operations/network', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新网络组件
|
||||
* @param data
|
||||
* @returns void
|
||||
*/
|
||||
export function networkUpdate(data: NetworkForm) {
|
||||
return requestClient.putWithMsg<void>('/operations/network', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除网络组件
|
||||
* @param id id
|
||||
* @returns void
|
||||
*/
|
||||
export function networkRemove(id: ID | IDS) {
|
||||
return requestClient.deleteWithMsg<void>(`/operations/network/${id}`);
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
import type { PageQuery, BaseEntity } from '#/api/common';
|
||||
|
||||
export interface NetworkVO {
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 启用状态 0 禁用
|
||||
*/
|
||||
enabled: string;
|
||||
|
||||
/**
|
||||
* 组件名称
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* 组件类型 HTTP_SERVER、MQTT_CLIENT 等
|
||||
*/
|
||||
networkType: string;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
description: string;
|
||||
|
||||
/**
|
||||
* 网络配置
|
||||
*/
|
||||
networkConfig: string;
|
||||
|
||||
}
|
||||
|
||||
export interface NetworkForm extends BaseEntity {
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 启用状态 0 禁用
|
||||
*/
|
||||
enabled?: string;
|
||||
|
||||
/**
|
||||
* 组件名称
|
||||
*/
|
||||
name?: string;
|
||||
|
||||
/**
|
||||
* 组件类型 HTTP_SERVER、MQTT_CLIENT 等
|
||||
*/
|
||||
networkType?: string;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* 网络配置
|
||||
*/
|
||||
networkConfig?: string;
|
||||
|
||||
}
|
||||
|
||||
export interface NetworkQuery extends PageQuery {
|
||||
/**
|
||||
* 启用状态 0 禁用
|
||||
*/
|
||||
enabled?: string;
|
||||
|
||||
/**
|
||||
* 组件名称
|
||||
*/
|
||||
name?: string;
|
||||
|
||||
/**
|
||||
* 组件类型 HTTP_SERVER、MQTT_CLIENT 等
|
||||
*/
|
||||
networkType?: string;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* 网络配置
|
||||
*/
|
||||
networkConfig?: string;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
import type { ProtocolVO, ProtocolForm, ProtocolQuery } from './model';
|
||||
|
||||
import type { ID, IDS } from '#/api/common';
|
||||
import type { PageResult } from '#/api/common';
|
||||
|
||||
import { commonExport } from '#/api/helper';
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
/**
|
||||
* 查询设备协议列表
|
||||
* @param params
|
||||
* @returns 设备协议列表
|
||||
*/
|
||||
export function protocolList(params?: ProtocolQuery) {
|
||||
return requestClient.get<PageResult<ProtocolVO>>('/operations/protocol/list', { params });
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出设备协议列表
|
||||
* @param params
|
||||
* @returns 设备协议列表
|
||||
*/
|
||||
export function protocolExport(params?: ProtocolQuery) {
|
||||
return commonExport('/operations/protocol/export', params ?? {});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询设备协议详情
|
||||
* @param id id
|
||||
* @returns 设备协议详情
|
||||
*/
|
||||
export function protocolInfo(id: ID) {
|
||||
return requestClient.get<ProtocolVO>(`/operations/protocol/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增设备协议
|
||||
* @param data
|
||||
* @returns void
|
||||
*/
|
||||
export function protocolAdd(data: ProtocolForm) {
|
||||
return requestClient.postWithMsg<void>('/operations/protocol', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新设备协议
|
||||
* @param data
|
||||
* @returns void
|
||||
*/
|
||||
export function protocolUpdate(data: ProtocolForm) {
|
||||
return requestClient.putWithMsg<void>('/operations/protocol', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除设备协议
|
||||
* @param id id
|
||||
* @returns void
|
||||
*/
|
||||
export function protocolRemove(id: ID | IDS) {
|
||||
return requestClient.deleteWithMsg<void>(`/operations/protocol/${id}`);
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
import type { PageQuery, BaseEntity } from '#/api/common';
|
||||
|
||||
export interface ProtocolVO {
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 启用状态 0 禁用
|
||||
*/
|
||||
enabled: string;
|
||||
|
||||
/**
|
||||
* 协议名称
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* 协议包类型 local、jar
|
||||
*/
|
||||
protocolType: string;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
description: string;
|
||||
|
||||
/**
|
||||
* 协议配置
|
||||
*/
|
||||
protocolConfig: string;
|
||||
|
||||
}
|
||||
|
||||
export interface ProtocolForm extends BaseEntity {
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 启用状态 0 禁用
|
||||
*/
|
||||
enabled?: string;
|
||||
|
||||
/**
|
||||
* 协议名称
|
||||
*/
|
||||
name?: string;
|
||||
|
||||
/**
|
||||
* 协议包类型 local、jar
|
||||
*/
|
||||
protocolType?: string;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* 协议配置
|
||||
*/
|
||||
protocolConfig?: string;
|
||||
|
||||
}
|
||||
|
||||
export interface ProtocolQuery extends PageQuery {
|
||||
/**
|
||||
* 启用状态 0 禁用
|
||||
*/
|
||||
enabled?: string;
|
||||
|
||||
/**
|
||||
* 协议名称
|
||||
*/
|
||||
name?: string;
|
||||
|
||||
/**
|
||||
* 协议包类型 local、jar
|
||||
*/
|
||||
protocolType?: string;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* 协议配置
|
||||
*/
|
||||
protocolConfig?: string;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
|
@ -30,6 +30,10 @@ export const overridesPreferences = defineOverridesPreferences({
|
|||
* 2. 切换租户登录后不会重新加载菜单
|
||||
*/
|
||||
// loginExpiredMode: 'modal',
|
||||
// 是否开启检查更新
|
||||
enableCheckUpdates: false,
|
||||
// 检查更新的时间间隔,单位为分钟
|
||||
checkUpdatesInterval: 1,
|
||||
},
|
||||
footer: {
|
||||
/**
|
||||
|
@ -42,6 +46,8 @@ export const overridesPreferences = defineOverridesPreferences({
|
|||
* 标签tab 持久化 关闭
|
||||
*/
|
||||
persist: false,
|
||||
// 隐藏tab显示
|
||||
enable: false,
|
||||
// styleType: 'card',
|
||||
},
|
||||
theme: {
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="p-4">
|
||||
<h1 class="text-2xl font-bold mb-4">Test Detail Page</h1>
|
||||
<p>This is a placeholder for the test detail page.</p>
|
||||
</div>
|
||||
</template>
|
|
@ -0,0 +1,170 @@
|
|||
import type { FormSchemaGetter } from '#/adapter/form';
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
|
||||
|
||||
export const querySchema: FormSchemaGetter = () => [
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'enabled',
|
||||
label: '启用状态 0 禁用',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'name',
|
||||
label: '网关名称',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'provider',
|
||||
label: '接入方式,如: mqtt-server-gateway',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'description',
|
||||
label: '描述',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'channel',
|
||||
label: '通道 接入通道(方式),如网络组件',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'channelId',
|
||||
label: '通道id 接入使用的通道ID,如: 网络组件ID,modbus通道ID',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'protocol',
|
||||
label: '消息协议 消息协议',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'transport',
|
||||
label: '传输协议,如TCP,MQTT,UDP',
|
||||
},
|
||||
{
|
||||
component: 'Textarea',
|
||||
fieldName: 'gatewayConfig',
|
||||
label: '网关配置',
|
||||
},
|
||||
];
|
||||
|
||||
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
|
||||
// export const columns: () => VxeGridProps['columns'] = () => [
|
||||
export const columns: VxeGridProps['columns'] = [
|
||||
{ type: 'checkbox', width: 60 },
|
||||
{
|
||||
title: '编号',
|
||||
field: 'id',
|
||||
},
|
||||
{
|
||||
title: '启用状态 0 禁用',
|
||||
field: 'enabled',
|
||||
},
|
||||
{
|
||||
title: '网关名称',
|
||||
field: 'name',
|
||||
},
|
||||
{
|
||||
title: '接入方式,如: mqtt-server-gateway',
|
||||
field: 'provider',
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
field: 'description',
|
||||
},
|
||||
{
|
||||
title: '通道 接入通道(方式),如网络组件',
|
||||
field: 'channel',
|
||||
},
|
||||
{
|
||||
title: '通道id 接入使用的通道ID,如: 网络组件ID,modbus通道ID',
|
||||
field: 'channelId',
|
||||
},
|
||||
{
|
||||
title: '消息协议 消息协议',
|
||||
field: 'protocol',
|
||||
},
|
||||
{
|
||||
title: '传输协议,如TCP,MQTT,UDP',
|
||||
field: 'transport',
|
||||
},
|
||||
{
|
||||
title: '网关配置',
|
||||
field: 'gatewayConfig',
|
||||
},
|
||||
{
|
||||
field: 'action',
|
||||
fixed: 'right',
|
||||
slots: { default: 'action' },
|
||||
title: '操作',
|
||||
width: 180,
|
||||
},
|
||||
];
|
||||
|
||||
export const drawerSchema: FormSchemaGetter = () => [
|
||||
{
|
||||
label: '编号',
|
||||
fieldName: 'id',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
show: () => false,
|
||||
triggerFields: [''],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '启用状态 0 禁用',
|
||||
fieldName: 'enabled',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '网关名称',
|
||||
fieldName: 'name',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '接入方式,如: mqtt-server-gateway',
|
||||
fieldName: 'provider',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '描述',
|
||||
fieldName: 'description',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '通道 接入通道(方式),如网络组件',
|
||||
fieldName: 'channel',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '通道id 接入使用的通道ID,如: 网络组件ID,modbus通道ID',
|
||||
fieldName: 'channelId',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '消息协议 消息协议',
|
||||
fieldName: 'protocol',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '传输协议,如TCP,MQTT,UDP',
|
||||
fieldName: 'transport',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '网关配置',
|
||||
fieldName: 'gatewayConfig',
|
||||
component: 'Textarea',
|
||||
rules: 'required',
|
||||
},
|
||||
];
|
|
@ -0,0 +1,101 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenDrawer } from '@vben/common-ui';
|
||||
import { $t } from '@vben/locales';
|
||||
import { cloneDeep } from '@vben/utils';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import { gatewayAdd, gatewayInfo, gatewayUpdate } from '#/api/operations/gateway';
|
||||
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
|
||||
|
||||
import { drawerSchema } from './data';
|
||||
|
||||
const emit = defineEmits<{ reload: [] }>();
|
||||
|
||||
const isUpdate = ref(false);
|
||||
const title = computed(() => {
|
||||
return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
|
||||
});
|
||||
|
||||
const [BasicForm, formApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
// 默认占满两列
|
||||
formItemClass: 'col-span-2',
|
||||
// 默认label宽度 px
|
||||
labelWidth: 80,
|
||||
// 通用配置项 会影响到所有表单项
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
}
|
||||
},
|
||||
schema: drawerSchema(),
|
||||
showDefaultActions: false,
|
||||
wrapperClass: 'grid-cols-2',
|
||||
});
|
||||
|
||||
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
|
||||
{
|
||||
initializedGetter: defaultFormValueGetter(formApi),
|
||||
currentGetter: defaultFormValueGetter(formApi),
|
||||
},
|
||||
);
|
||||
|
||||
const [BasicDrawer, drawerApi] = useVbenDrawer({
|
||||
// 在这里更改宽度
|
||||
class: 'w-[550px]',
|
||||
fullscreenButton: false,
|
||||
onBeforeClose,
|
||||
onClosed: handleClosed,
|
||||
onConfirm: handleConfirm,
|
||||
onOpenChange: async (isOpen) => {
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
drawerApi.drawerLoading(true);
|
||||
|
||||
const { id } = drawerApi.getData() as { id?: number | string };
|
||||
isUpdate.value = !!id;
|
||||
|
||||
if (isUpdate.value && id) {
|
||||
const record = await gatewayInfo(id);
|
||||
await formApi.setValues(record);
|
||||
}
|
||||
await markInitialized();
|
||||
|
||||
drawerApi.drawerLoading(false);
|
||||
},
|
||||
});
|
||||
|
||||
async function handleConfirm() {
|
||||
try {
|
||||
drawerApi.lock(true);
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
// getValues获取为一个readonly的对象 需要修改必须先深拷贝一次
|
||||
const data = cloneDeep(await formApi.getValues());
|
||||
await (isUpdate.value ? gatewayUpdate(data) : gatewayAdd(data));
|
||||
resetInitialized();
|
||||
emit('reload');
|
||||
drawerApi.close();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
drawerApi.lock(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleClosed() {
|
||||
await formApi.resetForm();
|
||||
resetInitialized();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicDrawer :title="title">
|
||||
<BasicForm />
|
||||
</BasicDrawer>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
<script setup lang="ts">
|
||||
import type { Recordable } from '@vben/types';
|
||||
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
|
||||
import { getVxePopupContainer } from '@vben/utils';
|
||||
|
||||
import { Modal, Popconfirm, Space } from 'ant-design-vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import {
|
||||
useVbenVxeGrid,
|
||||
vxeCheckboxChecked,
|
||||
type VxeGridProps
|
||||
} from '#/adapter/vxe-table';
|
||||
|
||||
import {
|
||||
gatewayExport,
|
||||
gatewayList,
|
||||
gatewayRemove,
|
||||
} from '#/api/operations/gateway';
|
||||
import type { GatewayForm } from '#/api/operations/gateway/model';
|
||||
import { commonDownloadExcel } from '#/utils/file/download';
|
||||
|
||||
import gatewayDrawer from './gateway-drawer.vue';
|
||||
import { columns, querySchema } from './data';
|
||||
|
||||
const formOptions: VbenFormProps = {
|
||||
commonConfig: {
|
||||
labelWidth: 80,
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
schema: querySchema(),
|
||||
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
|
||||
// 处理区间选择器RangePicker时间格式 将一个字段映射为两个字段 搜索/导出会用到
|
||||
// 不需要直接删除
|
||||
// fieldMappingTime: [
|
||||
// [
|
||||
// 'createTime',
|
||||
// ['params[beginTime]', 'params[endTime]'],
|
||||
// ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
|
||||
// ],
|
||||
// ],
|
||||
};
|
||||
|
||||
const gridOptions: VxeGridProps = {
|
||||
checkboxConfig: {
|
||||
// 高亮
|
||||
highlight: true,
|
||||
// 翻页时保留选中状态
|
||||
reserve: true,
|
||||
// 点击行选中
|
||||
// trigger: 'row',
|
||||
},
|
||||
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
|
||||
// columns: columns(),
|
||||
columns,
|
||||
height: 'auto',
|
||||
keepSource: true,
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues = {}) => {
|
||||
return await gatewayList({
|
||||
pageNum: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
},
|
||||
// 表格全局唯一表示 保存列配置需要用到
|
||||
id: 'operations-gateway-index'
|
||||
};
|
||||
|
||||
const [BasicTable, tableApi] = useVbenVxeGrid({
|
||||
formOptions,
|
||||
gridOptions,
|
||||
});
|
||||
|
||||
const [GatewayDrawer, drawerApi] = useVbenDrawer({
|
||||
connectedComponent: gatewayDrawer,
|
||||
});
|
||||
|
||||
function handleAdd() {
|
||||
drawerApi.setData({});
|
||||
drawerApi.open();
|
||||
}
|
||||
|
||||
async function handleEdit(row: Required<GatewayForm>) {
|
||||
drawerApi.setData({ id: row.id });
|
||||
drawerApi.open();
|
||||
}
|
||||
|
||||
async function handleDelete(row: Required<GatewayForm>) {
|
||||
await gatewayRemove(row.id);
|
||||
await tableApi.query();
|
||||
}
|
||||
|
||||
function handleMultiDelete() {
|
||||
const rows = tableApi.grid.getCheckboxRecords();
|
||||
const ids = rows.map((row: Required<GatewayForm>) => row.id);
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
okType: 'danger',
|
||||
content: `确认删除选中的${ids.length}条记录吗?`,
|
||||
onOk: async () => {
|
||||
await gatewayRemove(ids);
|
||||
await tableApi.query();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleDownloadExcel() {
|
||||
commonDownloadExcel(gatewayExport, '设备接入网关数据', tableApi.formApi.form.values, {
|
||||
fieldMappingTime: formOptions.fieldMappingTime,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page :auto-content-height="true">
|
||||
<BasicTable table-title="设备接入网关列表">
|
||||
<template #toolbar-tools>
|
||||
<Space>
|
||||
<a-button
|
||||
v-access:code="['operations:gateway:export']"
|
||||
@click="handleDownloadExcel"
|
||||
>
|
||||
{{ $t('pages.common.export') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
:disabled="!vxeCheckboxChecked(tableApi)"
|
||||
danger
|
||||
type="primary"
|
||||
v-access:code="['operations:gateway:remove']"
|
||||
@click="handleMultiDelete">
|
||||
{{ $t('pages.common.delete') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
v-access:code="['operations:gateway:add']"
|
||||
@click="handleAdd"
|
||||
>
|
||||
{{ $t('pages.common.add') }}
|
||||
</a-button>
|
||||
</Space>
|
||||
</template>
|
||||
<template #action="{ row }">
|
||||
<Space>
|
||||
<ghost-button
|
||||
v-access:code="['operations:gateway:edit']"
|
||||
@click.stop="handleEdit(row)"
|
||||
>
|
||||
{{ $t('pages.common.edit') }}
|
||||
</ghost-button>
|
||||
<Popconfirm
|
||||
:get-popup-container="getVxePopupContainer"
|
||||
placement="left"
|
||||
title="确认删除?"
|
||||
@confirm="handleDelete(row)"
|
||||
>
|
||||
<ghost-button
|
||||
danger
|
||||
v-access:code="['operations:gateway:remove']"
|
||||
@click.stop=""
|
||||
>
|
||||
{{ $t('pages.common.delete') }}
|
||||
</ghost-button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
</template>
|
||||
</BasicTable>
|
||||
<GatewayDrawer @reload="tableApi.query()" />
|
||||
</Page>
|
||||
</template>
|
|
@ -0,0 +1,348 @@
|
|||
import type { FormSchemaGetter } from '#/adapter/form';
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
|
||||
const networkTypeOptions = [
|
||||
{ label: 'MQTT客户端', value: 'MQTT_CLIENT' },
|
||||
{ label: 'HTTP服务', value: 'HTTP_SERVER' },
|
||||
];
|
||||
|
||||
const enabledOptions = [
|
||||
{ label: '启用', value: '1' },
|
||||
{ label: '禁用', value: '0' },
|
||||
];
|
||||
|
||||
// HTTP服务配置字段
|
||||
const httpServerFields = [
|
||||
{
|
||||
label: '本地地址',
|
||||
fieldName: 'localAddress',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入本地地址',
|
||||
disabled: true,
|
||||
},
|
||||
defaultValue: '0.0.0.0',
|
||||
help: '绑定到服务器上的网卡地址,绑定到所有网卡:0.0.0.0',
|
||||
rules: 'required',
|
||||
dependencies: {
|
||||
triggerFields: ['networkType'],
|
||||
show: (values: any) => values.networkType === 'HTTP_SERVER',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '本地端口',
|
||||
fieldName: 'localPort',
|
||||
component: 'InputNumber',
|
||||
componentProps: {
|
||||
placeholder: '请选择本地端口',
|
||||
min: 1,
|
||||
},
|
||||
rules: 'required',
|
||||
help: '监听指定端口的请求',
|
||||
dependencies: {
|
||||
triggerFields: ['networkType'],
|
||||
show: (values) => values.networkType === 'HTTP_SERVER',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '公网地址',
|
||||
fieldName: 'publicAddress',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入公网地址',
|
||||
},
|
||||
rules: 'required',
|
||||
help: '对外提供访问的地址,内网环境时填写服务器的内网IP地址',
|
||||
dependencies: {
|
||||
triggerFields: ['networkType'],
|
||||
show: (values) => values.networkType === 'HTTP_SERVER',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '公网端口',
|
||||
fieldName: 'publicPort',
|
||||
component: 'InputNumber',
|
||||
componentProps: {
|
||||
placeholder: '请输入端口',
|
||||
min: 1,
|
||||
},
|
||||
rules: 'required',
|
||||
help: '对外提供访问的端口',
|
||||
dependencies: {
|
||||
triggerFields: ['networkType'],
|
||||
show: (values) => values.networkType === 'HTTP_SERVER',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '开启TLS',
|
||||
fieldName: 'enableTls',
|
||||
component: 'RadioGroup',
|
||||
componentProps: {
|
||||
buttonStyle: 'solid',
|
||||
optionType: 'button',
|
||||
options: [
|
||||
{ label: '是', value: '1' },
|
||||
{ label: '否', value: '0' },
|
||||
],
|
||||
},
|
||||
defaultValue: '0',
|
||||
rules: 'required',
|
||||
dependencies: {
|
||||
triggerFields: ['networkType'],
|
||||
show: (values) => values.networkType === 'HTTP_SERVER',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
// MQTT客户端配置字段
|
||||
const mqttClientFields = [
|
||||
{
|
||||
label: '远程地址',
|
||||
fieldName: 'remoteAddress',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入远程地址',
|
||||
},
|
||||
rules: 'required',
|
||||
dependencies: {
|
||||
triggerFields: ['networkType'],
|
||||
show: (values: any) => values.networkType === 'MQTT_CLIENT',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '远程端口',
|
||||
fieldName: 'remotePort',
|
||||
component: 'InputNumber',
|
||||
componentProps: {
|
||||
placeholder: '请输入远程端口',
|
||||
min: 1,
|
||||
},
|
||||
rules: 'required',
|
||||
dependencies: {
|
||||
triggerFields: ['networkType'],
|
||||
show: (values: any) => values.networkType === 'MQTT_CLIENT',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'ClientId',
|
||||
fieldName: 'clientId',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入ClientId',
|
||||
},
|
||||
rules: 'required',
|
||||
dependencies: {
|
||||
triggerFields: ['networkType'],
|
||||
show: (values: any) => values.networkType === 'MQTT_CLIENT',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '用户名',
|
||||
fieldName: 'username',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入用户名',
|
||||
},
|
||||
rules: 'required',
|
||||
dependencies: {
|
||||
triggerFields: ['networkType'],
|
||||
show: (values: any) => values.networkType === 'MQTT_CLIENT',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '密码',
|
||||
fieldName: 'password',
|
||||
component: 'InputPassword',
|
||||
componentProps: {
|
||||
placeholder: '请输入密码',
|
||||
},
|
||||
rules: 'required',
|
||||
dependencies: {
|
||||
triggerFields: ['networkType'],
|
||||
show: (values: any) => values.networkType === 'MQTT_CLIENT',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '订阅前缀',
|
||||
fieldName: 'subscriptionPrefix',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入订阅前缀',
|
||||
},
|
||||
help: '当连接的服务为EMQ时,可能需要使用共享的订阅前缀,如:$queue或$share',
|
||||
rules: 'required',
|
||||
dependencies: {
|
||||
triggerFields: ['networkType'],
|
||||
show: (values: any) => values.networkType === 'MQTT_CLIENT',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '最大消息长度',
|
||||
fieldName: 'maxMessageLength',
|
||||
component: 'InputNumber',
|
||||
componentProps: {
|
||||
placeholder: '请输入最大消息长度',
|
||||
min: 1,
|
||||
},
|
||||
defaultValue: 8192,
|
||||
help: '单次收发消息的最大长度,单位:字节;设置过大可能会影响性能',
|
||||
rules: 'required',
|
||||
dependencies: {
|
||||
triggerFields: ['networkType'],
|
||||
show: (values: any) => values.networkType === 'MQTT_CLIENT',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '开启TLS',
|
||||
fieldName: 'enableTls',
|
||||
component: 'RadioGroup',
|
||||
componentProps: {
|
||||
buttonStyle: 'solid',
|
||||
optionType: 'button',
|
||||
options: [
|
||||
{ label: '是', value: '1' },
|
||||
{ label: '否', value: '0' },
|
||||
],
|
||||
},
|
||||
defaultValue: '0',
|
||||
rules: 'required',
|
||||
dependencies: {
|
||||
triggerFields: ['networkType'],
|
||||
show: (values: any) => values.networkType === 'MQTT_CLIENT',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const querySchema: FormSchemaGetter = () => [
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'name',
|
||||
label: '组件名称',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
filterOption: true,
|
||||
options: enabledOptions,
|
||||
placeholder: '请选择',
|
||||
showSearch: true,
|
||||
},
|
||||
fieldName: 'enabled',
|
||||
label: '启用状态',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
filterOption: true,
|
||||
options: networkTypeOptions,
|
||||
placeholder: '请选择',
|
||||
showSearch: true,
|
||||
},
|
||||
fieldName: 'networkType',
|
||||
label: '网络类型',
|
||||
},
|
||||
];
|
||||
|
||||
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
|
||||
// export const columns: () => VxeGridProps['columns'] = () => [
|
||||
export const columns: VxeGridProps['columns'] = [
|
||||
{ type: 'checkbox', width: 60 },
|
||||
{
|
||||
title: '编号',
|
||||
field: 'id',
|
||||
},
|
||||
{
|
||||
title: '组件名称',
|
||||
field: 'name',
|
||||
},
|
||||
{
|
||||
title: '网络类型',
|
||||
field: 'networkType',
|
||||
slots: { default: 'networkType' },
|
||||
},
|
||||
{
|
||||
title: '启用状态',
|
||||
field: 'enabled',
|
||||
slots: { default: 'enabled' },
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
field: 'description',
|
||||
},
|
||||
{
|
||||
field: 'action',
|
||||
fixed: 'right',
|
||||
slots: { default: 'action' },
|
||||
title: '操作',
|
||||
width: 180,
|
||||
},
|
||||
];
|
||||
|
||||
// 基础字段
|
||||
const baseFields = [
|
||||
{
|
||||
label: '编号',
|
||||
fieldName: 'id',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
show: () => false,
|
||||
triggerFields: [''],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '组件名称',
|
||||
fieldName: 'name',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入名称',
|
||||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '网络类型',
|
||||
fieldName: 'networkType',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
filterOption: true,
|
||||
options: networkTypeOptions,
|
||||
placeholder: '请选择网络类型',
|
||||
showSearch: true,
|
||||
},
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
label: '启用状态',
|
||||
fieldName: 'enabled',
|
||||
component: 'RadioGroup',
|
||||
componentProps: {
|
||||
buttonStyle: 'solid',
|
||||
options: enabledOptions,
|
||||
optionType: 'button',
|
||||
},
|
||||
defaultValue: '1',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '描述',
|
||||
fieldName: 'description',
|
||||
component: 'Textarea',
|
||||
componentProps: {
|
||||
placeholder: '请输入描述',
|
||||
rows: 3,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const drawerSchema: FormSchemaGetter = () => [
|
||||
...baseFields,
|
||||
// HTTP服务配置字段
|
||||
...httpServerFields,
|
||||
// MQTT客户端配置字段
|
||||
...mqttClientFields,
|
||||
];
|
||||
|
||||
// 导出字段配置供组件使用
|
||||
export { httpServerFields, mqttClientFields };
|
|
@ -0,0 +1,230 @@
|
|||
<script setup lang="ts">
|
||||
import type { VbenFormProps } from '@vben/common-ui';
|
||||
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
import type { NetworkForm } from '#/api/operations/network/model';
|
||||
|
||||
import { Page, useVbenDrawer } from '@vben/common-ui';
|
||||
import { getVxePopupContainer } from '@vben/utils';
|
||||
|
||||
import { Modal, Popconfirm, Space, Tag } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid, vxeCheckboxChecked } from '#/adapter/vxe-table';
|
||||
import {
|
||||
networkExport,
|
||||
networkList,
|
||||
networkRemove,
|
||||
} from '#/api/operations/network';
|
||||
import { commonDownloadExcel } from '#/utils/file/download';
|
||||
|
||||
import { columns, querySchema } from './data';
|
||||
import networkDrawer from './network-drawer.vue';
|
||||
|
||||
const formOptions: VbenFormProps = {
|
||||
commonConfig: {
|
||||
labelWidth: 80,
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
schema: querySchema(),
|
||||
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
|
||||
// 处理区间选择器RangePicker时间格式 将一个字段映射为两个字段 搜索/导出会用到
|
||||
// 不需要直接删除
|
||||
// fieldMappingTime: [
|
||||
// [
|
||||
// 'createTime',
|
||||
// ['params[beginTime]', 'params[endTime]'],
|
||||
// ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
|
||||
// ],
|
||||
// ],
|
||||
};
|
||||
|
||||
const gridOptions: VxeGridProps = {
|
||||
checkboxConfig: {
|
||||
// 高亮
|
||||
highlight: true,
|
||||
// 翻页时保留选中状态
|
||||
reserve: true,
|
||||
// 点击行选中
|
||||
// trigger: 'row',
|
||||
},
|
||||
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
|
||||
// columns: columns(),
|
||||
columns,
|
||||
height: 'auto',
|
||||
keepSource: true,
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues = {}) => {
|
||||
return await networkList({
|
||||
pageNum: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
},
|
||||
// 表格全局唯一表示 保存列配置需要用到
|
||||
id: 'operations-network-index',
|
||||
};
|
||||
|
||||
const [BasicTable, tableApi] = useVbenVxeGrid({
|
||||
formOptions,
|
||||
gridOptions,
|
||||
});
|
||||
|
||||
const [NetworkDrawer, drawerApi] = useVbenDrawer({
|
||||
connectedComponent: networkDrawer,
|
||||
});
|
||||
|
||||
function handleAdd() {
|
||||
drawerApi.setData({});
|
||||
drawerApi.open();
|
||||
}
|
||||
|
||||
async function handleEdit(row: Required<NetworkForm>) {
|
||||
drawerApi.setData({ id: row.id });
|
||||
drawerApi.open();
|
||||
}
|
||||
|
||||
async function handleDelete(row: Required<NetworkForm>) {
|
||||
await networkRemove(row.id);
|
||||
await tableApi.query();
|
||||
}
|
||||
|
||||
function handleMultiDelete() {
|
||||
const rows = tableApi.grid.getCheckboxRecords();
|
||||
const ids = rows.map((row: Required<NetworkForm>) => row.id);
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
okType: 'danger',
|
||||
content: `确认删除选中的${ids.length}条记录吗?`,
|
||||
onOk: async () => {
|
||||
await networkRemove(ids);
|
||||
await tableApi.query();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleDownloadExcel() {
|
||||
commonDownloadExcel(
|
||||
networkExport,
|
||||
'网络组件数据',
|
||||
tableApi.formApi.form.values,
|
||||
{
|
||||
fieldMappingTime: formOptions.fieldMappingTime,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// 解析网络配置JSON
|
||||
function parseNetworkConfig(networkConfig: string) {
|
||||
try {
|
||||
return JSON.parse(networkConfig);
|
||||
} catch (error) {
|
||||
console.error('解析网络配置失败:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化网络配置显示
|
||||
function formatNetworkConfig(row: any) {
|
||||
const config = parseNetworkConfig(row.networkConfig);
|
||||
if (!config) {
|
||||
return '配置解析失败';
|
||||
}
|
||||
|
||||
if (row.networkType === 'HTTP_SERVER') {
|
||||
return `本地: ${config.localAddress}:${config.localPort} | 公网: ${config.publicAddress}:${config.publicPort} | TLS: ${config.enableTls === '1' ? '是' : '否'}`;
|
||||
} else if (row.networkType === 'MQTT_CLIENT') {
|
||||
return `远程: ${config.remoteAddress}:${config.remotePort} | ClientId: ${config.clientId} | TLS: ${config.enableTls === '1' ? '是' : '否'}`;
|
||||
}
|
||||
|
||||
return '未知配置';
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page :auto-content-height="true">
|
||||
<BasicTable table-title="网络组件列表">
|
||||
<template #toolbar-tools>
|
||||
<Space>
|
||||
<a-button
|
||||
v-access:code="['operations:network:export']"
|
||||
@click="handleDownloadExcel"
|
||||
>
|
||||
{{ $t('pages.common.export') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
:disabled="!vxeCheckboxChecked(tableApi)"
|
||||
danger
|
||||
type="primary"
|
||||
v-access:code="['operations:network:remove']"
|
||||
@click="handleMultiDelete"
|
||||
>
|
||||
{{ $t('pages.common.delete') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
v-access:code="['operations:network:add']"
|
||||
@click="handleAdd"
|
||||
>
|
||||
{{ $t('pages.common.add') }}
|
||||
</a-button>
|
||||
</Space>
|
||||
</template>
|
||||
<template #networkType="{ row }">
|
||||
<Tag color="processing">{{ row.networkType }}</Tag>
|
||||
</template>
|
||||
<template #enabled="{ row }">
|
||||
<Tag :color="row.enabled === '1' ? 'success' : 'error'">
|
||||
{{ row.enabled === '1' ? '启用' : '禁用' }}
|
||||
</Tag>
|
||||
</template>
|
||||
<template #action="{ row }">
|
||||
<Space>
|
||||
<ghost-button
|
||||
v-access:code="['operations:network:edit']"
|
||||
@click.stop="handleEdit(row)"
|
||||
>
|
||||
{{ $t('pages.common.edit') }}
|
||||
</ghost-button>
|
||||
<Popconfirm
|
||||
:get-popup-container="getVxePopupContainer"
|
||||
placement="left"
|
||||
title="确认删除?"
|
||||
@confirm="handleDelete(row)"
|
||||
>
|
||||
<ghost-button
|
||||
danger
|
||||
v-access:code="['operations:network:remove']"
|
||||
@click.stop=""
|
||||
>
|
||||
{{ $t('pages.common.delete') }}
|
||||
</ghost-button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
</template>
|
||||
</BasicTable>
|
||||
<NetworkDrawer @reload="tableApi.query()" />
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.network-config-display {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.config-summary {
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,147 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenDrawer } from '@vben/common-ui';
|
||||
import { $t } from '@vben/locales';
|
||||
import { cloneDeep } from '@vben/utils';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import {
|
||||
networkAdd,
|
||||
networkInfo,
|
||||
networkUpdate,
|
||||
} from '#/api/operations/network';
|
||||
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
|
||||
|
||||
import { drawerSchema } from './data';
|
||||
|
||||
const emit = defineEmits<{ reload: [] }>();
|
||||
|
||||
const isUpdate = ref(false);
|
||||
const title = computed(() => {
|
||||
return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
|
||||
});
|
||||
|
||||
const [BasicForm, formApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
// 默认占满两列
|
||||
formItemClass: 'col-span-2',
|
||||
// 默认label宽度 px
|
||||
labelWidth: 100,
|
||||
// 通用配置项 会影响到所有表单项
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
},
|
||||
},
|
||||
schema: drawerSchema(),
|
||||
showDefaultActions: false,
|
||||
wrapperClass: 'grid-cols-2',
|
||||
});
|
||||
|
||||
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
|
||||
{
|
||||
initializedGetter: defaultFormValueGetter(formApi),
|
||||
currentGetter: defaultFormValueGetter(formApi),
|
||||
},
|
||||
);
|
||||
|
||||
const [BasicDrawer, drawerApi] = useVbenDrawer({
|
||||
// 在这里更改宽度
|
||||
class: 'w-[800px]',
|
||||
fullscreenButton: false,
|
||||
onBeforeClose,
|
||||
onClosed: handleClosed,
|
||||
onConfirm: handleConfirm,
|
||||
onOpenChange: async (isOpen) => {
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
drawerApi.drawerLoading(true);
|
||||
|
||||
const { id } = drawerApi.getData() as { id?: number | string };
|
||||
isUpdate.value = !!id;
|
||||
|
||||
if (isUpdate.value && id) {
|
||||
const record = await networkInfo(id);
|
||||
|
||||
// 解析网络配置JSON
|
||||
if (record.networkConfig) {
|
||||
try {
|
||||
const configData = JSON.parse(record.networkConfig);
|
||||
// 将解析的配置数据合并到表单中
|
||||
const formData = { ...record, ...configData };
|
||||
await formApi.setValues(formData);
|
||||
} catch (error) {
|
||||
console.error('解析网络配置失败:', error);
|
||||
await formApi.setValues(record);
|
||||
}
|
||||
} else {
|
||||
await formApi.setValues(record);
|
||||
}
|
||||
} else {
|
||||
// 确保表单有初始值
|
||||
await formApi.setValues({
|
||||
networkType: 'MQTT_CLIENT',
|
||||
});
|
||||
}
|
||||
|
||||
await markInitialized();
|
||||
drawerApi.drawerLoading(false);
|
||||
},
|
||||
});
|
||||
|
||||
async function handleConfirm() {
|
||||
try {
|
||||
drawerApi.lock(true);
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
// getValues获取为一个readonly的对象 需要修改必须先深拷贝一次
|
||||
const formData = cloneDeep(await formApi.getValues());
|
||||
|
||||
// 分离基础字段和配置字段
|
||||
const baseFields = new Set([
|
||||
'description',
|
||||
'enabled',
|
||||
'id',
|
||||
'name',
|
||||
'networkType',
|
||||
]);
|
||||
const baseData: any = {};
|
||||
const configData: any = {};
|
||||
|
||||
Object.keys(formData).forEach((key) => {
|
||||
if (baseFields.has(key)) {
|
||||
baseData[key] = formData[key];
|
||||
} else {
|
||||
configData[key] = formData[key];
|
||||
}
|
||||
});
|
||||
|
||||
// 将配置字段转换为JSON字符串
|
||||
baseData.networkConfig = JSON.stringify(configData);
|
||||
|
||||
await (isUpdate.value ? networkUpdate(baseData) : networkAdd(baseData));
|
||||
resetInitialized();
|
||||
emit('reload');
|
||||
drawerApi.close();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
drawerApi.lock(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleClosed() {
|
||||
await formApi.resetForm();
|
||||
resetInitialized();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicDrawer :title="title">
|
||||
<BasicForm />
|
||||
</BasicDrawer>
|
||||
</template>
|
|
@ -0,0 +1,138 @@
|
|||
import type { FormSchemaGetter } from '#/adapter/form';
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
|
||||
const enabledOptions = [
|
||||
{ label: '启用', value: '1' },
|
||||
{ label: '禁用', value: '0' },
|
||||
];
|
||||
|
||||
const protocolTypeOptions = [
|
||||
{ label: 'local', value: 'local' },
|
||||
{ label: 'jar', value: 'jar' },
|
||||
];
|
||||
|
||||
export const querySchema: FormSchemaGetter = () => [
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'name',
|
||||
label: '协议名称',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
filterOption: true,
|
||||
options: protocolTypeOptions,
|
||||
placeholder: '请选择',
|
||||
showSearch: true,
|
||||
},
|
||||
fieldName: 'protocolType',
|
||||
label: '协议包类型',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
filterOption: true,
|
||||
options: enabledOptions,
|
||||
placeholder: '请选择',
|
||||
showSearch: true,
|
||||
},
|
||||
fieldName: 'enabled',
|
||||
label: '启用状态',
|
||||
},
|
||||
];
|
||||
|
||||
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
|
||||
// export const columns: () => VxeGridProps['columns'] = () => [
|
||||
export const columns: VxeGridProps['columns'] = [
|
||||
{ type: 'checkbox', width: 60 },
|
||||
{
|
||||
title: '编号',
|
||||
field: 'id',
|
||||
},
|
||||
{
|
||||
title: '协议名称',
|
||||
field: 'name',
|
||||
},
|
||||
{
|
||||
title: '协议包类型',
|
||||
slots: { default: 'protocolType' },
|
||||
field: 'protocolType',
|
||||
},
|
||||
{
|
||||
title: '协议配置',
|
||||
field: 'protocolConfig',
|
||||
},
|
||||
{
|
||||
title: '启用状态',
|
||||
slots: { default: 'enabled' },
|
||||
field: 'enabled',
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
field: 'description',
|
||||
},
|
||||
{
|
||||
field: 'action',
|
||||
fixed: 'right',
|
||||
slots: { default: 'action' },
|
||||
title: '操作',
|
||||
width: 180,
|
||||
},
|
||||
];
|
||||
|
||||
export const drawerSchema: FormSchemaGetter = () => [
|
||||
{
|
||||
label: '编号',
|
||||
fieldName: 'id',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
show: () => false,
|
||||
triggerFields: [''],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '协议名称',
|
||||
fieldName: 'name',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '协议包类型',
|
||||
fieldName: 'protocolType',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
filterOption: true,
|
||||
options: protocolTypeOptions,
|
||||
placeholder: '请选择',
|
||||
showSearch: true,
|
||||
},
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
label: '协议配置',
|
||||
fieldName: 'protocolConfig',
|
||||
component: 'Textarea',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '启用状态',
|
||||
fieldName: 'enabled',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
filterOption: true,
|
||||
options: enabledOptions,
|
||||
placeholder: '请选择',
|
||||
showSearch: true,
|
||||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '描述',
|
||||
fieldName: 'description',
|
||||
component: 'Textarea',
|
||||
},
|
||||
];
|
|
@ -0,0 +1,190 @@
|
|||
<script setup lang="ts">
|
||||
import type { VbenFormProps } from '@vben/common-ui';
|
||||
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
import type { ProtocolForm } from '#/api/operations/protocol/model';
|
||||
|
||||
import { Page, useVbenDrawer } from '@vben/common-ui';
|
||||
import { getVxePopupContainer } from '@vben/utils';
|
||||
|
||||
import { Modal, Popconfirm, Space, Tag } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid, vxeCheckboxChecked } from '#/adapter/vxe-table';
|
||||
import {
|
||||
protocolExport,
|
||||
protocolList,
|
||||
protocolRemove,
|
||||
} from '#/api/operations/protocol';
|
||||
import { commonDownloadExcel } from '#/utils/file/download';
|
||||
|
||||
import { columns, querySchema } from './data';
|
||||
import protocolDrawer from './protocol-drawer.vue';
|
||||
|
||||
const formOptions: VbenFormProps = {
|
||||
commonConfig: {
|
||||
labelWidth: 80,
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
schema: querySchema(),
|
||||
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
|
||||
// 处理区间选择器RangePicker时间格式 将一个字段映射为两个字段 搜索/导出会用到
|
||||
// 不需要直接删除
|
||||
// fieldMappingTime: [
|
||||
// [
|
||||
// 'createTime',
|
||||
// ['params[beginTime]', 'params[endTime]'],
|
||||
// ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
|
||||
// ],
|
||||
// ],
|
||||
};
|
||||
|
||||
const gridOptions: VxeGridProps = {
|
||||
checkboxConfig: {
|
||||
// 高亮
|
||||
highlight: true,
|
||||
// 翻页时保留选中状态
|
||||
reserve: true,
|
||||
// 点击行选中
|
||||
// trigger: 'row',
|
||||
},
|
||||
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
|
||||
// columns: columns(),
|
||||
columns,
|
||||
height: 'auto',
|
||||
keepSource: true,
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues = {}) => {
|
||||
return await protocolList({
|
||||
pageNum: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
},
|
||||
// 表格全局唯一表示 保存列配置需要用到
|
||||
id: 'operations-protocol-index',
|
||||
};
|
||||
|
||||
const [BasicTable, tableApi] = useVbenVxeGrid({
|
||||
formOptions,
|
||||
gridOptions,
|
||||
});
|
||||
|
||||
const [ProtocolDrawer, drawerApi] = useVbenDrawer({
|
||||
connectedComponent: protocolDrawer,
|
||||
});
|
||||
|
||||
function handleAdd() {
|
||||
drawerApi.setData({});
|
||||
drawerApi.open();
|
||||
}
|
||||
|
||||
async function handleEdit(row: Required<ProtocolForm>) {
|
||||
drawerApi.setData({ id: row.id });
|
||||
drawerApi.open();
|
||||
}
|
||||
|
||||
async function handleDelete(row: Required<ProtocolForm>) {
|
||||
await protocolRemove(row.id);
|
||||
await tableApi.query();
|
||||
}
|
||||
|
||||
function handleMultiDelete() {
|
||||
const rows = tableApi.grid.getCheckboxRecords();
|
||||
const ids = rows.map((row: Required<ProtocolForm>) => row.id);
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
okType: 'danger',
|
||||
content: `确认删除选中的${ids.length}条记录吗?`,
|
||||
onOk: async () => {
|
||||
await protocolRemove(ids);
|
||||
await tableApi.query();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleDownloadExcel() {
|
||||
commonDownloadExcel(
|
||||
protocolExport,
|
||||
'设备协议数据',
|
||||
tableApi.formApi.form.values,
|
||||
{
|
||||
fieldMappingTime: formOptions.fieldMappingTime,
|
||||
},
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page :auto-content-height="true">
|
||||
<BasicTable table-title="设备协议列表">
|
||||
<template #toolbar-tools>
|
||||
<Space>
|
||||
<a-button
|
||||
v-access:code="['operations:protocol:export']"
|
||||
@click="handleDownloadExcel"
|
||||
>
|
||||
{{ $t('pages.common.export') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
:disabled="!vxeCheckboxChecked(tableApi)"
|
||||
danger
|
||||
type="primary"
|
||||
v-access:code="['operations:protocol:remove']"
|
||||
@click="handleMultiDelete"
|
||||
>
|
||||
{{ $t('pages.common.delete') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
v-access:code="['operations:protocol:add']"
|
||||
@click="handleAdd"
|
||||
>
|
||||
{{ $t('pages.common.add') }}
|
||||
</a-button>
|
||||
</Space>
|
||||
</template>
|
||||
<template #protocolType="{ row }">
|
||||
<Tag color="processing">{{ row.protocolType }}</Tag>
|
||||
</template>
|
||||
<template #enabled="{ row }">
|
||||
<Tag :color="row.enabled === '1' ? 'success' : 'error'">
|
||||
{{ row.enabled === '1' ? '启用' : '禁用' }}
|
||||
</Tag>
|
||||
</template>
|
||||
<template #action="{ row }">
|
||||
<Space>
|
||||
<ghost-button
|
||||
v-access:code="['operations:protocol:edit']"
|
||||
@click.stop="handleEdit(row)"
|
||||
>
|
||||
{{ $t('pages.common.edit') }}
|
||||
</ghost-button>
|
||||
<Popconfirm
|
||||
:get-popup-container="getVxePopupContainer"
|
||||
placement="left"
|
||||
title="确认删除?"
|
||||
@confirm="handleDelete(row)"
|
||||
>
|
||||
<ghost-button
|
||||
danger
|
||||
v-access:code="['operations:protocol:remove']"
|
||||
@click.stop=""
|
||||
>
|
||||
{{ $t('pages.common.delete') }}
|
||||
</ghost-button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
</template>
|
||||
</BasicTable>
|
||||
<ProtocolDrawer @reload="tableApi.query()" />
|
||||
</Page>
|
||||
</template>
|
|
@ -0,0 +1,101 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenDrawer } from '@vben/common-ui';
|
||||
import { $t } from '@vben/locales';
|
||||
import { cloneDeep } from '@vben/utils';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import { protocolAdd, protocolInfo, protocolUpdate } from '#/api/operations/protocol';
|
||||
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
|
||||
|
||||
import { drawerSchema } from './data';
|
||||
|
||||
const emit = defineEmits<{ reload: [] }>();
|
||||
|
||||
const isUpdate = ref(false);
|
||||
const title = computed(() => {
|
||||
return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
|
||||
});
|
||||
|
||||
const [BasicForm, formApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
// 默认占满两列
|
||||
formItemClass: 'col-span-2',
|
||||
// 默认label宽度 px
|
||||
labelWidth: 80,
|
||||
// 通用配置项 会影响到所有表单项
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
}
|
||||
},
|
||||
schema: drawerSchema(),
|
||||
showDefaultActions: false,
|
||||
wrapperClass: 'grid-cols-2',
|
||||
});
|
||||
|
||||
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
|
||||
{
|
||||
initializedGetter: defaultFormValueGetter(formApi),
|
||||
currentGetter: defaultFormValueGetter(formApi),
|
||||
},
|
||||
);
|
||||
|
||||
const [BasicDrawer, drawerApi] = useVbenDrawer({
|
||||
// 在这里更改宽度
|
||||
class: 'w-[550px]',
|
||||
fullscreenButton: false,
|
||||
onBeforeClose,
|
||||
onClosed: handleClosed,
|
||||
onConfirm: handleConfirm,
|
||||
onOpenChange: async (isOpen) => {
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
drawerApi.drawerLoading(true);
|
||||
|
||||
const { id } = drawerApi.getData() as { id?: number | string };
|
||||
isUpdate.value = !!id;
|
||||
|
||||
if (isUpdate.value && id) {
|
||||
const record = await protocolInfo(id);
|
||||
await formApi.setValues(record);
|
||||
}
|
||||
await markInitialized();
|
||||
|
||||
drawerApi.drawerLoading(false);
|
||||
},
|
||||
});
|
||||
|
||||
async function handleConfirm() {
|
||||
try {
|
||||
drawerApi.lock(true);
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
// getValues获取为一个readonly的对象 需要修改必须先深拷贝一次
|
||||
const data = cloneDeep(await formApi.getValues());
|
||||
await (isUpdate.value ? protocolUpdate(data) : protocolAdd(data));
|
||||
resetInitialized();
|
||||
emit('reload');
|
||||
drawerApi.close();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
drawerApi.lock(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleClosed() {
|
||||
await formApi.resetForm();
|
||||
resetInitialized();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicDrawer :title="title">
|
||||
<BasicForm />
|
||||
</BasicDrawer>
|
||||
</template>
|
||||
|
Loading…
Reference in New Issue