批量设备添加
This commit is contained in:
parent
934043edde
commit
d241a1a6b9
@ -1231,7 +1231,7 @@ export const CreateDeviceAggregationInputSchema = {
|
||||
ioTPlatformProductId: {
|
||||
minLength: 1,
|
||||
type: 'string',
|
||||
description: '集中器在物联网平台中对应的产品Id'
|
||||
description: '设备在物联网平台中对应的产品Id'
|
||||
},
|
||||
deviceSourceTypeEnum: {
|
||||
'$ref': '#/components/schemas/DeviceSourceTypeEnum'
|
||||
@ -4551,154 +4551,62 @@ JiShe.ServicePro.Enums.DeviceTypeEnum`,
|
||||
description: '设备路径,树模型使用,表模型会在数据插入的时候直接获取继承类的名称作为表明',
|
||||
nullable: true
|
||||
},
|
||||
scoreValue: {
|
||||
productId: {
|
||||
type: 'string',
|
||||
description: '排序索引分数值,具体值可以根据不同业务场景进行定义,例如时间戳、或者某一个固定的标识',
|
||||
description: '物联网平台产品Id',
|
||||
nullable: true
|
||||
},
|
||||
packetType: {
|
||||
platformDeviceId: {
|
||||
type: 'string',
|
||||
description: '物联网平台设备ID',
|
||||
nullable: true
|
||||
},
|
||||
messageType: {
|
||||
type: 'string',
|
||||
description: '消息类型',
|
||||
nullable: true
|
||||
},
|
||||
rawMessage: {
|
||||
type: 'string',
|
||||
description: '下发消息体原始内容',
|
||||
nullable: true
|
||||
},
|
||||
issuePayload: {
|
||||
type: 'string',
|
||||
description: '下发消息体',
|
||||
nullable: true
|
||||
},
|
||||
responseRawMessage: {
|
||||
type: 'string',
|
||||
description: '下发结果原始内容',
|
||||
nullable: true
|
||||
},
|
||||
responseResult: {
|
||||
type: 'string',
|
||||
description: '下发结果',
|
||||
nullable: true
|
||||
},
|
||||
telemetrySource: {
|
||||
type: 'integer',
|
||||
description: '数据包类型',
|
||||
description: '遥测指令来源',
|
||||
format: 'int32'
|
||||
},
|
||||
manualOrNot: {
|
||||
type: 'boolean',
|
||||
description: '是否手动操作'
|
||||
},
|
||||
taskMark: {
|
||||
telemetrySourceName: {
|
||||
type: 'string',
|
||||
description: '任务数据唯一标记',
|
||||
nullable: true
|
||||
description: '遥测指令来源',
|
||||
nullable: true,
|
||||
readOnly: true
|
||||
},
|
||||
isTimeout: {
|
||||
type: 'boolean',
|
||||
description: '是否超时'
|
||||
},
|
||||
pendingCopyReadTime: {
|
||||
type: 'string',
|
||||
description: '待抄读时间',
|
||||
format: 'date-time'
|
||||
},
|
||||
focusId: {
|
||||
ioTPlatform: {
|
||||
type: 'integer',
|
||||
description: '集中器Id',
|
||||
description: `设备指令发送平台
|
||||
IoTPlatformTypeEnum`,
|
||||
format: 'int32'
|
||||
},
|
||||
focusAddress: {
|
||||
ioTPlatformName: {
|
||||
type: 'string',
|
||||
description: '集中器地址',
|
||||
nullable: true
|
||||
},
|
||||
meterAddress: {
|
||||
type: 'string',
|
||||
description: '表地址',
|
||||
nullable: true
|
||||
},
|
||||
databaseBusiID: {
|
||||
type: 'integer',
|
||||
description: '数据库业务ID',
|
||||
format: 'int32'
|
||||
},
|
||||
afn: {
|
||||
type: 'integer',
|
||||
description: 'AFN功能码',
|
||||
format: 'int32'
|
||||
},
|
||||
fn: {
|
||||
type: 'integer',
|
||||
description: '抄读功能码',
|
||||
format: 'int32'
|
||||
},
|
||||
pn: {
|
||||
type: 'integer',
|
||||
description: '抄读计量点',
|
||||
format: 'int32'
|
||||
},
|
||||
itemCode: {
|
||||
type: 'string',
|
||||
description: '采集项编码',
|
||||
nullable: true
|
||||
},
|
||||
subItemCode: {
|
||||
type: 'string',
|
||||
description: '子项编码,一般用于透明转发的编码',
|
||||
nullable: true
|
||||
},
|
||||
seq: {
|
||||
type: 'integer',
|
||||
description: '帧序列域 SEQ',
|
||||
format: 'int32'
|
||||
},
|
||||
msa: {
|
||||
type: 'integer',
|
||||
description: '地址域A3的主站地址MSA',
|
||||
format: 'int32'
|
||||
},
|
||||
isSend: {
|
||||
type: 'boolean',
|
||||
description: '是否发送'
|
||||
},
|
||||
sendNum: {
|
||||
type: 'integer',
|
||||
description: '发送次数',
|
||||
format: 'int32',
|
||||
nullable: true
|
||||
},
|
||||
nextSendTime: {
|
||||
type: 'string',
|
||||
description: '下次发送时间',
|
||||
format: 'date-time',
|
||||
nullable: true
|
||||
},
|
||||
creationTime: {
|
||||
type: 'string',
|
||||
description: '创建时间',
|
||||
format: 'date-time'
|
||||
},
|
||||
issuedMessageHexString: {
|
||||
type: 'string',
|
||||
description: '下发消息内容',
|
||||
nullable: true
|
||||
},
|
||||
issuedMessageId: {
|
||||
type: 'string',
|
||||
description: '下发消息Id',
|
||||
nullable: true
|
||||
},
|
||||
focusDensity: {
|
||||
type: 'integer',
|
||||
description: '集中器采集密度',
|
||||
format: 'int32'
|
||||
},
|
||||
receivedMessageHexString: {
|
||||
type: 'string',
|
||||
description: '消息上报内容',
|
||||
nullable: true
|
||||
},
|
||||
receivedTime: {
|
||||
type: 'string',
|
||||
description: '消息上报时间',
|
||||
format: 'date-time',
|
||||
nullable: true
|
||||
},
|
||||
receivedMessageId: {
|
||||
type: 'string',
|
||||
description: '上报消息Id',
|
||||
nullable: true
|
||||
},
|
||||
receivedRemark: {
|
||||
type: 'string',
|
||||
description: '上报报文解析备注,异常情况下才有',
|
||||
nullable: true
|
||||
},
|
||||
isReceived: {
|
||||
type: 'boolean',
|
||||
description: '是否已上报'
|
||||
},
|
||||
times: {
|
||||
type: 'string',
|
||||
description: '时标',
|
||||
format: 'date-time',
|
||||
description: '设备指令发送平台',
|
||||
nullable: true,
|
||||
readOnly: true
|
||||
}
|
||||
},
|
||||
|
||||
@ -224,7 +224,7 @@ export type CreateDeviceAggregationInput = {
|
||||
deviceAddress: string;
|
||||
ioTPlatform: IoTPlatformTypeEnum;
|
||||
/**
|
||||
* 集中器在物联网平台中对应的产品Id
|
||||
* 设备在物联网平台中对应的产品Id
|
||||
*/
|
||||
ioTPlatformProductId: string;
|
||||
deviceSourceTypeEnum?: DeviceSourceTypeEnum;
|
||||
@ -2187,125 +2187,50 @@ export type MeterReadingPacketInfoPageOutput = {
|
||||
*/
|
||||
devicePath?: (string) | null;
|
||||
/**
|
||||
* 排序索引分数值,具体值可以根据不同业务场景进行定义,例如时间戳、或者某一个固定的标识
|
||||
* 物联网平台产品Id
|
||||
*/
|
||||
scoreValue?: (string) | null;
|
||||
productId?: (string) | null;
|
||||
/**
|
||||
* 数据包类型
|
||||
* 物联网平台设备ID
|
||||
*/
|
||||
packetType?: number;
|
||||
platformDeviceId?: (string) | null;
|
||||
/**
|
||||
* 是否手动操作
|
||||
* 消息类型
|
||||
*/
|
||||
manualOrNot?: boolean;
|
||||
messageType?: (string) | null;
|
||||
/**
|
||||
* 任务数据唯一标记
|
||||
* 下发消息体原始内容
|
||||
*/
|
||||
taskMark?: (string) | null;
|
||||
rawMessage?: (string) | null;
|
||||
/**
|
||||
* 是否超时
|
||||
* 下发消息体
|
||||
*/
|
||||
isTimeout?: boolean;
|
||||
issuePayload?: (string) | null;
|
||||
/**
|
||||
* 待抄读时间
|
||||
* 下发结果原始内容
|
||||
*/
|
||||
pendingCopyReadTime?: string;
|
||||
responseRawMessage?: (string) | null;
|
||||
/**
|
||||
* 集中器Id
|
||||
* 下发结果
|
||||
*/
|
||||
focusId?: number;
|
||||
responseResult?: (string) | null;
|
||||
/**
|
||||
* 集中器地址
|
||||
* 遥测指令来源
|
||||
*/
|
||||
focusAddress?: (string) | null;
|
||||
telemetrySource?: number;
|
||||
/**
|
||||
* 表地址
|
||||
* 遥测指令来源
|
||||
*/
|
||||
meterAddress?: (string) | null;
|
||||
readonly telemetrySourceName?: (string) | null;
|
||||
/**
|
||||
* 数据库业务ID
|
||||
* 设备指令发送平台
|
||||
* IoTPlatformTypeEnum
|
||||
*/
|
||||
databaseBusiID?: number;
|
||||
ioTPlatform?: number;
|
||||
/**
|
||||
* AFN功能码
|
||||
* 设备指令发送平台
|
||||
*/
|
||||
afn?: number;
|
||||
/**
|
||||
* 抄读功能码
|
||||
*/
|
||||
fn?: number;
|
||||
/**
|
||||
* 抄读计量点
|
||||
*/
|
||||
pn?: number;
|
||||
/**
|
||||
* 采集项编码
|
||||
*/
|
||||
itemCode?: (string) | null;
|
||||
/**
|
||||
* 子项编码,一般用于透明转发的编码
|
||||
*/
|
||||
subItemCode?: (string) | null;
|
||||
/**
|
||||
* 帧序列域 SEQ
|
||||
*/
|
||||
seq?: number;
|
||||
/**
|
||||
* 地址域A3的主站地址MSA
|
||||
*/
|
||||
msa?: number;
|
||||
/**
|
||||
* 是否发送
|
||||
*/
|
||||
isSend?: boolean;
|
||||
/**
|
||||
* 发送次数
|
||||
*/
|
||||
sendNum?: (number) | null;
|
||||
/**
|
||||
* 下次发送时间
|
||||
*/
|
||||
nextSendTime?: (string) | null;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
creationTime?: string;
|
||||
/**
|
||||
* 下发消息内容
|
||||
*/
|
||||
issuedMessageHexString?: (string) | null;
|
||||
/**
|
||||
* 下发消息Id
|
||||
*/
|
||||
issuedMessageId?: (string) | null;
|
||||
/**
|
||||
* 集中器采集密度
|
||||
*/
|
||||
focusDensity?: number;
|
||||
/**
|
||||
* 消息上报内容
|
||||
*/
|
||||
receivedMessageHexString?: (string) | null;
|
||||
/**
|
||||
* 消息上报时间
|
||||
*/
|
||||
receivedTime?: (string) | null;
|
||||
/**
|
||||
* 上报消息Id
|
||||
*/
|
||||
receivedMessageId?: (string) | null;
|
||||
/**
|
||||
* 上报报文解析备注,异常情况下才有
|
||||
*/
|
||||
receivedRemark?: (string) | null;
|
||||
/**
|
||||
* 是否已上报
|
||||
*/
|
||||
isReceived?: boolean;
|
||||
/**
|
||||
* 时标
|
||||
*/
|
||||
readonly times?: string;
|
||||
readonly ioTPlatformName?: (string) | null;
|
||||
};
|
||||
|
||||
export type MeterReadingPacketInfoPageOutputPagedResultDto = {
|
||||
|
||||
@ -20,6 +20,7 @@ import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import {
|
||||
postAggregationDeviceCreateAsync,
|
||||
postAggregationDeviceDeleteAsync,
|
||||
postAggregationDeviceBatchCreateAsync,
|
||||
postDeviceInfoCacheDeviceDataToRedis,
|
||||
postDeviceInfoPage,
|
||||
} from '#/api-client';
|
||||
@ -30,6 +31,7 @@ import { $t } from '#/locales';
|
||||
|
||||
import {
|
||||
addDeviceFormSchema,
|
||||
batchAddDeviceFormSchema,
|
||||
commandFormSchema,
|
||||
editDeviceFormSchemaEdit,
|
||||
querySchema,
|
||||
@ -150,6 +152,31 @@ const [CommandForm, commandFormApi] = useVbenForm({
|
||||
showDefaultActions: false,
|
||||
});
|
||||
|
||||
const [BatchAddForm, batchAddFormApi] = useVbenForm({
|
||||
// 默认展开
|
||||
collapsed: false,
|
||||
// 所有表单项共用,可单独在表单内覆盖
|
||||
commonConfig: {
|
||||
labelWidth: 110,
|
||||
componentProps: {
|
||||
class: 'w-4/5',
|
||||
},
|
||||
},
|
||||
layout: 'horizontal',
|
||||
schema: batchAddDeviceFormSchema.value,
|
||||
showCollapseButton: false,
|
||||
showDefaultActions: false,
|
||||
wrapperClass: 'grid-cols-2',
|
||||
});
|
||||
|
||||
const [BatchAddModal, batchAddModalApi] = useVbenModal({
|
||||
draggable: true,
|
||||
onConfirm: submitBatchAdd,
|
||||
onBeforeClose: () => {
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
// 新增和编辑提交的逻辑
|
||||
async function submit() {
|
||||
const isEdit = !!editRow.value.id;
|
||||
@ -339,20 +366,94 @@ async function submitCommand() {
|
||||
}
|
||||
}
|
||||
|
||||
// 批量添加设备提交逻辑
|
||||
async function submitBatchAdd() {
|
||||
const { valid } = await batchAddFormApi.validate();
|
||||
if (!valid) return;
|
||||
|
||||
const formValues = await batchAddFormApi.getValues();
|
||||
|
||||
// 处理设备地址列表
|
||||
const addressList = formValues.addressList
|
||||
.split('\n')
|
||||
.map((address: string) => address.trim())
|
||||
.filter((address: string) => address.length > 0);
|
||||
|
||||
if (addressList.length === 0) {
|
||||
Message.error('请输入至少一个设备地址');
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证设备地址格式(简单验证)
|
||||
const invalidAddresses = addressList.filter((address: string) => !address || address.length < 3);
|
||||
if (invalidAddresses.length > 0) {
|
||||
Message.error(`以下设备地址格式不正确: ${invalidAddresses.join(', ')}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据平台类型处理数据
|
||||
let ioTPlatformProductId = '';
|
||||
if (formValues.ioTPlatform === 2 || formValues.ioTPlatform === '2') {
|
||||
// OneNET平台
|
||||
ioTPlatformProductId = formValues.oneNETProductId;
|
||||
} else if (formValues.ioTPlatform === 1 || formValues.ioTPlatform === '1') {
|
||||
// CTWing平台
|
||||
ioTPlatformProductId = formValues.ctWingProductId;
|
||||
}
|
||||
|
||||
if (!ioTPlatformProductId) {
|
||||
Message.error('请选择产品');
|
||||
return;
|
||||
}
|
||||
|
||||
const batchCreateParams = {
|
||||
addressList,
|
||||
ioTPlatform: formValues.ioTPlatform,
|
||||
ioTPlatformProductId,
|
||||
};
|
||||
|
||||
try {
|
||||
batchAddModalApi.setState({ loading: true, confirmLoading: true });
|
||||
const resp = await postAggregationDeviceBatchCreateAsync({
|
||||
body: batchCreateParams,
|
||||
});
|
||||
if (resp.data) {
|
||||
Message.success(`批量添加设备成功,共添加 ${addressList.length} 个设备`);
|
||||
batchAddModalApi.close();
|
||||
batchAddFormApi.resetForm();
|
||||
gridApi.reload();
|
||||
} else {
|
||||
Message.error('批量添加设备失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('批量添加设备失败:', error);
|
||||
Message.error('批量添加设备失败');
|
||||
} finally {
|
||||
batchAddModalApi.setState({ loading: false, confirmLoading: false });
|
||||
}
|
||||
}
|
||||
|
||||
// 打开批量添加模态框
|
||||
const openBatchAddModal = () => {
|
||||
batchAddFormApi.resetForm();
|
||||
batchAddModalApi.open();
|
||||
};
|
||||
|
||||
// 缓存刷新按钮处理函数
|
||||
const handleCacheRefresh = async () => {
|
||||
if (cacheRefreshLoading.value) return; // 防止重复点击
|
||||
|
||||
try {
|
||||
cacheRefreshLoading.value = true;
|
||||
pageLoading.value = true;
|
||||
try {
|
||||
await postDeviceInfoCacheDeviceDataToRedis({
|
||||
body: {},
|
||||
});
|
||||
Message.success($t('common.operationSuccess'));
|
||||
const result = await postDeviceInfoCacheDeviceDataToRedis();
|
||||
if (result.data) {
|
||||
Message.success('缓存刷新成功');
|
||||
gridApi.reload();
|
||||
} else {
|
||||
Message.error('缓存刷新失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('缓存刷新失败:', error);
|
||||
Message.error($t('common.operationFailed'));
|
||||
Message.error('缓存刷新失败');
|
||||
} finally {
|
||||
cacheRefreshLoading.value = false;
|
||||
pageLoading.value = false;
|
||||
@ -368,11 +469,18 @@ const toolbarActions = computed(() => [
|
||||
onClick: openAddModal.bind(null),
|
||||
auth: ['AbpIdentity.Users.Create'],
|
||||
},
|
||||
{
|
||||
label: '批量添加',
|
||||
type: 'primary',
|
||||
icon: 'ant-design:plus-outlined',
|
||||
onClick: openBatchAddModal.bind(null),
|
||||
auth: ['AbpIdentity.Users.Create'],
|
||||
},
|
||||
{
|
||||
label: cacheRefreshLoading.value
|
||||
? $t('common.loading')
|
||||
: $t('abp.IoTDBBase.CacheRefresh'),
|
||||
type: 'primary',
|
||||
type: 'default',
|
||||
icon: cacheRefreshLoading.value
|
||||
? 'ant-design:loading-outlined'
|
||||
: 'ant-design:reload-outlined',
|
||||
@ -460,14 +568,8 @@ const toolbarActions = computed(() => [
|
||||
style=" padding: 4px 8px;text-align: left">
|
||||
{{ $t('abp.IoTDBBase.TelemetryLog') }}
|
||||
</Button>
|
||||
<Button type="text" size="small" @click="
|
||||
() => {
|
||||
Modal.confirm({
|
||||
title: $t('common.askConfirmDelete'),
|
||||
onOk: () => onDel(row),
|
||||
});
|
||||
}
|
||||
" style=" padding: 4px 8px; color: #ff4d4f;text-align: left">
|
||||
<Button type="text" size="small" @click="onDel.bind(null, row)()"
|
||||
style=" padding: 4px 8px; color: #ff4d4f;text-align: left">
|
||||
{{ $t('common.delete') }}
|
||||
</Button>
|
||||
</div>
|
||||
@ -487,5 +589,8 @@ const toolbarActions = computed(() => [
|
||||
<CommandModal :title="$t('abp.IoTDBBase.Command')" class="w-[600px]">
|
||||
<CommandForm />
|
||||
</CommandModal>
|
||||
<BatchAddModal title="批量添加设备" class="w-[800px]">
|
||||
<BatchAddForm />
|
||||
</BatchAddModal>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
@ -665,3 +665,292 @@ export const commandFormSchema: any = computed(() => [
|
||||
}),
|
||||
},
|
||||
]);
|
||||
|
||||
export const batchAddDeviceFormSchema: any = computed(() => [
|
||||
{
|
||||
component: 'ApiSelect',
|
||||
fieldName: 'ioTPlatform',
|
||||
label: $t('abp.deviceInfos.ioTPlatform'),
|
||||
componentProps: {
|
||||
api: getCommonGetSelectList,
|
||||
params: {
|
||||
query: {
|
||||
typeName: 'IoTPlatformTypeEnum',
|
||||
},
|
||||
},
|
||||
labelField: 'value',
|
||||
valueField: 'key',
|
||||
optionsPropName: 'options',
|
||||
immediate: true,
|
||||
allowClear: true,
|
||||
placeholder:
|
||||
$t('common.pleaseSelect') + $t('abp.deviceInfos.ioTPlatform'),
|
||||
afterFetch: (res: any) => {
|
||||
// 确保返回的是数组格式
|
||||
if (Array.isArray(res)) {
|
||||
return res;
|
||||
}
|
||||
// 如果是包装在 items 中的,提取出来
|
||||
if (res && Array.isArray(res.items)) {
|
||||
return res.items;
|
||||
}
|
||||
// 如果是包装在 data 中的,提取出来
|
||||
if (res && Array.isArray(res.data)) {
|
||||
return res.data;
|
||||
}
|
||||
// 如果都不是,返回空数组
|
||||
return [];
|
||||
},
|
||||
},
|
||||
rules: z.string().min(1, {
|
||||
message: `${$t('common.pleaseSelect')}${$t('abp.deviceInfos.ioTPlatform')}`,
|
||||
}),
|
||||
},
|
||||
{
|
||||
component: 'ApiSelect',
|
||||
fieldName: 'oneNETAccountId',
|
||||
label: $t('abp.deviceInfos.ioTPlatformAccountName'),
|
||||
dependencies: {
|
||||
show(values: any) {
|
||||
return values.ioTPlatform === 2 || values.ioTPlatform === '2'; // OneNET平台
|
||||
},
|
||||
rules(values: any) {
|
||||
if (values.ioTPlatform === 2 || values.ioTPlatform === '2') {
|
||||
return 'required';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
triggerFields: ['ioTPlatform'],
|
||||
},
|
||||
componentProps: {
|
||||
api: postOneNetAccountListAsync,
|
||||
params: {
|
||||
body: {
|
||||
pageIndex: 1,
|
||||
pageSize: 1000,
|
||||
},
|
||||
},
|
||||
labelField: 'accountName',
|
||||
valueField: 'oneNETAccountId',
|
||||
immediate: true,
|
||||
afterFetch: (res: any) => {
|
||||
// 如果是 Axios 响应对象,提取 data
|
||||
if (res && res.data) {
|
||||
const data = res.data;
|
||||
|
||||
// 确保返回的是数组格式
|
||||
if (Array.isArray(data)) {
|
||||
return data;
|
||||
}
|
||||
// 如果是包装在 items 中的,提取出来
|
||||
if (data && Array.isArray(data.items)) {
|
||||
return data.items;
|
||||
}
|
||||
// 如果是包装在 data 中的,提取出来
|
||||
if (data && Array.isArray(data.data)) {
|
||||
return data.data;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果都不是,返回空数组
|
||||
return [];
|
||||
},
|
||||
placeholder: `${$t('common.pleaseSelect')}${$t('abp.deviceInfos.ioTPlatformAccountName')}`,
|
||||
},
|
||||
rules: z.string().optional(),
|
||||
},
|
||||
{
|
||||
component: 'ApiSelect',
|
||||
fieldName: 'ctWingAccountId',
|
||||
label: $t('abp.deviceInfos.ioTPlatformAccountName'),
|
||||
dependencies: {
|
||||
show(values: any) {
|
||||
return values.ioTPlatform === 1 || values.ioTPlatform === '1'; // CTWing平台
|
||||
},
|
||||
rules(values: any) {
|
||||
if (values.ioTPlatform === 1 || values.ioTPlatform === '1') {
|
||||
return 'required';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
triggerFields: ['ioTPlatform'], // 添加这一行,使其能够响应平台切换
|
||||
},
|
||||
componentProps: {
|
||||
api: postCtWingAccountListAsync,
|
||||
params: {
|
||||
body: {
|
||||
pageIndex: 1,
|
||||
pageSize: 1000,
|
||||
},
|
||||
},
|
||||
labelField: 'accountName',
|
||||
valueField: 'accountId',
|
||||
immediate: true,
|
||||
afterFetch: (res: any) => {
|
||||
// 如果是 Axios 响应对象,提取 data
|
||||
if (res && res.data) {
|
||||
const data = res.data;
|
||||
|
||||
// 确保返回的是数组格式
|
||||
if (Array.isArray(data)) {
|
||||
return data;
|
||||
}
|
||||
// 如果是包装在 items 中的,提取出来
|
||||
if (data && Array.isArray(data.items)) {
|
||||
return data.items;
|
||||
}
|
||||
// 如果是包装在 data 中的,提取出来
|
||||
if (data && Array.isArray(data.data)) {
|
||||
return data.data;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果都不是,返回空数组
|
||||
return [];
|
||||
},
|
||||
placeholder: `${$t('common.pleaseSelect')}${$t('abp.deviceInfos.ioTPlatformAccountName')}`,
|
||||
},
|
||||
rules: z.string().optional(),
|
||||
},
|
||||
{
|
||||
component: 'ApiSelect',
|
||||
fieldName: 'oneNETProductId',
|
||||
label: $t('abp.deviceInfos.ioTPlatformProductName'),
|
||||
dependencies: {
|
||||
show(values: any) {
|
||||
return (
|
||||
(values.ioTPlatform === 2 || values.ioTPlatform === '2') &&
|
||||
values.oneNETAccountId
|
||||
); // OneNET平台且已选择账号
|
||||
},
|
||||
rules(values: any) {
|
||||
if (
|
||||
(values.ioTPlatform === 2 || values.ioTPlatform === '2') &&
|
||||
values.oneNETAccountId
|
||||
) {
|
||||
return 'required';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
triggerFields: ['ioTPlatform', 'oneNETAccountId'],
|
||||
},
|
||||
componentProps: {
|
||||
api: postOneNetProductListAsync,
|
||||
params: (formValues: any) => ({
|
||||
body: {
|
||||
pageIndex: 1,
|
||||
pageSize: 1000,
|
||||
oneNETAccountId: formValues.oneNETAccountId,
|
||||
},
|
||||
}),
|
||||
labelField: 'productName',
|
||||
valueField: 'ioTPlatformProductId',
|
||||
immediate: true,
|
||||
afterFetch: (res: any) => {
|
||||
// 如果是 Axios 响应对象,提取 data
|
||||
if (res && res.data) {
|
||||
const data = res.data;
|
||||
|
||||
// 确保返回的是数组格式
|
||||
let items = [];
|
||||
if (Array.isArray(data)) {
|
||||
items = data;
|
||||
} else if (data && Array.isArray(data.items)) {
|
||||
items = data.items;
|
||||
} else if (data && Array.isArray(data.data)) {
|
||||
items = data.data;
|
||||
}
|
||||
|
||||
// 为每个产品项添加组合标签
|
||||
return items.map((item: any) => ({
|
||||
...item,
|
||||
label: `${item.productName || ''} (${item.ioTPlatformProductId || ''})`,
|
||||
}));
|
||||
}
|
||||
|
||||
// 如果都不是,返回空数组
|
||||
return [];
|
||||
},
|
||||
placeholder: `${$t('common.pleaseSelect')}${$t('abp.deviceInfos.ioTPlatformProductName')}`,
|
||||
},
|
||||
rules: z.string().optional(),
|
||||
},
|
||||
{
|
||||
component: 'ApiSelect',
|
||||
fieldName: 'ctWingProductId',
|
||||
label: $t('abp.deviceInfos.ioTPlatformProductName'),
|
||||
dependencies: {
|
||||
show(values: any) {
|
||||
return (
|
||||
(values.ioTPlatform === 1 || values.ioTPlatform === '1') &&
|
||||
values.ctWingAccountId
|
||||
); // CTWing平台且已选择账号
|
||||
},
|
||||
rules(values: any) {
|
||||
if (
|
||||
(values.ioTPlatform === 1 || values.ioTPlatform === '1') &&
|
||||
values.ctWingAccountId
|
||||
) {
|
||||
return 'required';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
triggerFields: ['ioTPlatform', 'ctWingAccountId'],
|
||||
},
|
||||
componentProps: {
|
||||
api: postCtWingProductListAsync,
|
||||
params: (formValues: any) => ({
|
||||
body: {
|
||||
pageIndex: 1,
|
||||
pageSize: 1000,
|
||||
ctWingAccountId: formValues.ctWingAccountId,
|
||||
},
|
||||
}),
|
||||
labelField: 'productName',
|
||||
valueField: 'ioTPlatformProductId',
|
||||
immediate: true,
|
||||
afterFetch: (res: any) => {
|
||||
// 如果是 Axios 响应对象,提取 data
|
||||
if (res && res.data) {
|
||||
const data = res.data;
|
||||
|
||||
// 确保返回的是数组格式
|
||||
let items = [];
|
||||
if (Array.isArray(data)) {
|
||||
items = data;
|
||||
} else if (data && Array.isArray(data.items)) {
|
||||
items = data.items;
|
||||
} else if (data && Array.isArray(data.data)) {
|
||||
items = data.data;
|
||||
}
|
||||
|
||||
// 为每个产品项添加组合标签,并确保产品ID是字符串类型
|
||||
return items.map((item: any) => ({
|
||||
...item,
|
||||
ioTPlatformProductId: String(item.ioTPlatformProductId || ''),
|
||||
label: `${item.productName || ''} (${item.ioTPlatformProductId || ''})`,
|
||||
}));
|
||||
}
|
||||
|
||||
// 如果都不是,返回空数组
|
||||
return [];
|
||||
},
|
||||
placeholder: `${$t('common.pleaseSelect')}${$t('abp.deviceInfos.ioTPlatformProductName')}`,
|
||||
},
|
||||
rules: z.string().optional(),
|
||||
},
|
||||
{
|
||||
component: 'Textarea',
|
||||
fieldName: 'addressList',
|
||||
label: $t('abp.deviceInfos.deviceAddress'),
|
||||
componentProps: {
|
||||
rows: 8,
|
||||
placeholder: $t('common.pleaseInput') + $t('abp.deviceInfos.deviceAddress') + ',每行一个设备地址',
|
||||
showCount: true,
|
||||
maxLength: 2000,
|
||||
},
|
||||
rules: z.string().min(1, {
|
||||
message: `${$t('common.pleaseInput')}${$t('abp.deviceInfos.deviceAddress')}`,
|
||||
}),
|
||||
},
|
||||
]);
|
||||
|
||||
@ -67,7 +67,7 @@ const getDeviceInfoByAddress = (deviceAddress: string) => {
|
||||
const formOptions: VbenFormProps = {
|
||||
schema: querySchema.value,
|
||||
initialValues: {
|
||||
DeviceAddress: DeviceAddress as string,
|
||||
deviceAddress: DeviceAddress as string,
|
||||
},
|
||||
// 禁用表单值变化时自动提交,使用自定义处理函数
|
||||
submitOnChange: false,
|
||||
@ -78,9 +78,9 @@ const formOptions: VbenFormProps = {
|
||||
return;
|
||||
}
|
||||
|
||||
// 当 DeviceAddress 发生变化时,更新 selectedDeviceInfo
|
||||
if (changedFields.includes('DeviceAddress')) {
|
||||
const deviceAddress = values.DeviceAddress;
|
||||
// 当 deviceAddress 发生变化时,更新 selectedDeviceInfo
|
||||
if (changedFields.includes('deviceAddress')) {
|
||||
const deviceAddress = values.deviceAddress;
|
||||
|
||||
if (deviceAddress) {
|
||||
// 先尝试从 deviceOptions 中查找(备用方案)
|
||||
@ -94,7 +94,7 @@ const formOptions: VbenFormProps = {
|
||||
try {
|
||||
// 获取 DeviceSelect 组件的实例
|
||||
const deviceSelectRef =
|
||||
gridApi.formApi.getFieldComponentRef('DeviceAddress');
|
||||
gridApi.formApi.getFieldComponentRef('deviceAddress');
|
||||
if (deviceSelectRef && deviceSelectRef.getSelectedDevice) {
|
||||
device = deviceSelectRef.getSelectedDevice();
|
||||
}
|
||||
@ -110,7 +110,7 @@ const formOptions: VbenFormProps = {
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const deviceSelectRef =
|
||||
gridApi.formApi.getFieldComponentRef('DeviceAddress');
|
||||
gridApi.formApi.getFieldComponentRef('deviceAddress');
|
||||
if (deviceSelectRef && deviceSelectRef.getSelectedDevice) {
|
||||
const delayedDevice = deviceSelectRef.getSelectedDevice();
|
||||
if (delayedDevice) {
|
||||
@ -167,13 +167,13 @@ const gridOptions: VxeGridProps<any> = {
|
||||
// 总是从表单API获取最新的表单值,确保分页时参数完整
|
||||
const currentFormValues = gridApi?.formApi ? await gridApi.formApi.getValues() : {};
|
||||
|
||||
// 如果表单中没有DeviceAddress,但有路由参数,使用路由参数
|
||||
if (!currentFormValues.DeviceAddress && DeviceAddress) {
|
||||
currentFormValues.DeviceAddress = DeviceAddress as string;
|
||||
// 如果表单中没有deviceAddress,但有路由参数,使用路由参数
|
||||
if (!currentFormValues.deviceAddress && DeviceAddress) {
|
||||
currentFormValues.deviceAddress = DeviceAddress as string;
|
||||
}
|
||||
|
||||
// 获取选中的设备信息
|
||||
let deviceAddress = currentFormValues.DeviceAddress || '';
|
||||
let deviceAddress = currentFormValues.deviceAddress || '';
|
||||
|
||||
// 优先使用选中的设备信息
|
||||
const deviceInfo =
|
||||
@ -190,9 +190,7 @@ const gridOptions: VxeGridProps<any> = {
|
||||
const queryParams = {
|
||||
pageIndex: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
DeviceAddress: deviceAddress,
|
||||
focusAddress: currentFormValues.focusAddress || '',
|
||||
meterAddress: currentFormValues.meterAddress || '',
|
||||
deviceAddress: deviceAddress,
|
||||
};
|
||||
|
||||
const { data } = await postTableModelPacketInfoPage({
|
||||
@ -222,10 +220,10 @@ const initializeGrid = async () => {
|
||||
if (gridApi && gridApi.formApi) {
|
||||
// 确保表单值正确设置
|
||||
const currentValues = await gridApi.formApi.getValues();
|
||||
if (!currentValues.DeviceAddress && DeviceAddress) {
|
||||
if (!currentValues.deviceAddress && DeviceAddress) {
|
||||
await gridApi.formApi.setValues({
|
||||
...currentValues,
|
||||
DeviceAddress: DeviceAddress as string,
|
||||
deviceAddress: DeviceAddress as string,
|
||||
});
|
||||
}
|
||||
// 延迟清除初始化标志,确保只触发一次查询
|
||||
@ -285,34 +283,10 @@ onMounted(async () => {
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<Grid>
|
||||
<template #DeviceAddress="{ model, field }">
|
||||
<template #deviceAddress="{ model, field }">
|
||||
<DeviceSelect ref="deviceSelectRef" v-model:value="model[field]"
|
||||
:placeholder="$t('common.pleaseSelect') + $t('abp.log.deviceInfo')" allow-clear />
|
||||
</template>
|
||||
<template #ismanualOrNot="{ row }">
|
||||
<component :is="h(Tag, { color: row.manualOrNot ? 'green' : 'red' }, () =>
|
||||
row.manualOrNot ? $t('common.yes') : $t('common.no'),
|
||||
)
|
||||
" />
|
||||
</template>
|
||||
<template #isTimeout="{ row }">
|
||||
<component :is="h(Tag, { color: row.isTimeout ? 'green' : 'red' }, () =>
|
||||
row.isTimeout ? $t('common.yes') : $t('common.no'),
|
||||
)
|
||||
" />
|
||||
</template>
|
||||
<template #isSend="{ row }">
|
||||
<component :is="h(Tag, { color: row.isSend ? 'green' : 'red' }, () =>
|
||||
row.isSend ? $t('common.yes') : $t('common.no'),
|
||||
)
|
||||
" />
|
||||
</template>
|
||||
<template #isReceived="{ row }">
|
||||
<component :is="h(Tag, { color: row.isReceived ? 'green' : 'red' }, () =>
|
||||
row.isReceived ? $t('common.yes') : $t('common.no'),
|
||||
)
|
||||
" />
|
||||
</template>
|
||||
</Grid>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
@ -7,93 +7,80 @@ import { $t } from '#/locales';
|
||||
export const querySchema = computed(() => [
|
||||
{
|
||||
component: 'DeviceSelect',
|
||||
fieldName: 'DeviceAddress',
|
||||
fieldName: 'deviceAddress',
|
||||
label: $t('abp.log.deviceInfo'),
|
||||
componentProps: {
|
||||
placeholder: $t('common.pleaseSelect') + $t('abp.log.deviceInfo'),
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'focusAddress',
|
||||
label: $t('abp.focus.focusAddress'),
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'meterAddress',
|
||||
label: $t('abp.meters.meterAddress'),
|
||||
},
|
||||
]);
|
||||
|
||||
export const tableSchema: any = computed((): VxeGridProps['columns'] => [
|
||||
{ title: $t('common.seq'), type: 'seq', width: 50 },
|
||||
{
|
||||
field: 'ioTDataType',
|
||||
title: $t('abp.IoTDBBase.IoTDataType'),
|
||||
minWidth: '120',
|
||||
},
|
||||
{
|
||||
field: 'deviceType',
|
||||
title: $t('abp.IoTDBBase.DeviceType'),
|
||||
minWidth: '120',
|
||||
},
|
||||
{
|
||||
field: 'deviceAddress',
|
||||
title: $t('abp.focus.focusAddress'),
|
||||
minWidth: '100',
|
||||
title: $t('abp.IoTDBBase.DeviceAddress'),
|
||||
minWidth: '120',
|
||||
},
|
||||
{
|
||||
field: 'timestamps',
|
||||
title: $t('abp.log.timestamps'),
|
||||
minWidth: '100',
|
||||
},
|
||||
{
|
||||
field: 'manualOrNot',
|
||||
title: $t('abp.log.manualOrNot'),
|
||||
minWidth: '150',
|
||||
slots: { default: 'ismanualOrNot' },
|
||||
},
|
||||
{
|
||||
field: 'isTimeout',
|
||||
title: $t('abp.log.isTimeout'),
|
||||
minWidth: '150',
|
||||
slots: { default: 'isTimeout' },
|
||||
},
|
||||
{ field: 'afn', title: $t('abp.log.afn'), minWidth: '150' },
|
||||
{ field: 'fn', title: $t('abp.log.fn'), minWidth: '100' },
|
||||
{ field: 'pn', title: $t('abp.log.pn'), minWidth: '100' },
|
||||
{ field: 'itemCode', title: $t('abp.log.itemCode'), minWidth: '100' },
|
||||
{
|
||||
field: 'isSend',
|
||||
title: $t('abp.log.isSend'),
|
||||
minWidth: '150',
|
||||
slots: { default: 'isSend' },
|
||||
},
|
||||
{
|
||||
field: 'sendNum',
|
||||
title: $t('abp.log.sendNum'),
|
||||
minWidth: '100',
|
||||
},
|
||||
{
|
||||
field: 'nextSendTime',
|
||||
title: $t('abp.log.nextSendTime'),
|
||||
field: 'formattedTimestamps',
|
||||
title: $t('abp.IoTDBBase.FormattedTimestamps'),
|
||||
minWidth: '150',
|
||||
},
|
||||
{
|
||||
field: 'issuedMessageHexString',
|
||||
field: 'productId',
|
||||
title: $t('abp.CTWingLog.ProductId'),
|
||||
minWidth: '120',
|
||||
},
|
||||
{
|
||||
field: 'platformDeviceId',
|
||||
title: $t('abp.CTWingLog.PlatformDeviceId'),
|
||||
minWidth: '150',
|
||||
},
|
||||
{
|
||||
field: 'messageType',
|
||||
title: $t('abp.CTWingLog.MessageType'),
|
||||
minWidth: '120',
|
||||
},
|
||||
{
|
||||
field: 'rawMessage',
|
||||
title: $t('abp.CTWingLog.RawMessage'),
|
||||
minWidth: '200',
|
||||
},
|
||||
{
|
||||
field: 'issuePayload',
|
||||
title: $t('abp.log.issuedMessageHexString'),
|
||||
minWidth: '150',
|
||||
minWidth: '200',
|
||||
},
|
||||
{
|
||||
field: 'receivedMessageHexString',
|
||||
field: 'responseRawMessage',
|
||||
title: $t('abp.log.receivedMessageHexString'),
|
||||
minWidth: '150',
|
||||
minWidth: '200',
|
||||
},
|
||||
{
|
||||
field: 'receivedTime',
|
||||
title: $t('abp.log.receivedTime'),
|
||||
minWidth: '150',
|
||||
},
|
||||
{
|
||||
field: 'isReceived',
|
||||
title: $t('abp.log.isReceived'),
|
||||
minWidth: '150',
|
||||
slots: { default: 'isReceived' },
|
||||
},
|
||||
{
|
||||
field: 'receivedRemark',
|
||||
field: 'responseResult',
|
||||
title: $t('abp.log.receivedRemark'),
|
||||
minWidth: '150',
|
||||
},
|
||||
{
|
||||
field: 'telemetrySourceName',
|
||||
title: $t('abp.log.manualOrNot'),
|
||||
minWidth: '120',
|
||||
},
|
||||
{
|
||||
field: 'ioTPlatformName',
|
||||
title: $t('abp.deviceInfos.ioTPlatformName'),
|
||||
minWidth: '120',
|
||||
},
|
||||
]);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user