2025-06-25 17:29:57 +08:00
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
|
import type { VbenFormProps } from '#/adapter/form';
|
|
|
|
|
|
import type { VxeGridProps } from '#/adapter/vxe-table';
|
|
|
|
|
|
|
2025-08-05 10:57:01 +08:00
|
|
|
|
import { computed, h, ref, watch } from 'vue';
|
2025-06-25 17:29:57 +08:00
|
|
|
|
import { useRouter } from 'vue-router';
|
|
|
|
|
|
|
|
|
|
|
|
import { Page, useVbenModal } from '@vben/common-ui';
|
|
|
|
|
|
|
2025-08-01 17:36:42 +08:00
|
|
|
|
import {
|
|
|
|
|
|
Button,
|
|
|
|
|
|
message as Message,
|
|
|
|
|
|
Modal,
|
|
|
|
|
|
Popover,
|
|
|
|
|
|
Tag,
|
|
|
|
|
|
} from 'ant-design-vue';
|
2025-06-25 17:29:57 +08:00
|
|
|
|
|
|
|
|
|
|
import { useVbenForm } from '#/adapter/form';
|
|
|
|
|
|
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
|
|
|
|
|
import {
|
2025-08-05 10:57:01 +08:00
|
|
|
|
postAggregationDeviceBatchCreateAsync,
|
2025-07-28 14:38:00 +08:00
|
|
|
|
postAggregationDeviceCreateAsync,
|
|
|
|
|
|
postAggregationDeviceDeleteAsync,
|
2025-08-01 14:58:48 +08:00
|
|
|
|
postDeviceInfoCacheDeviceDataToRedis,
|
2025-07-25 17:27:41 +08:00
|
|
|
|
postDeviceInfoPage,
|
2025-07-28 14:38:00 +08:00
|
|
|
|
} from '#/api-client';
|
2025-08-01 17:36:42 +08:00
|
|
|
|
import { Icon } from '#/components/icon';
|
|
|
|
|
|
import { Loading } from '#/components/Loading';
|
2025-06-25 17:29:57 +08:00
|
|
|
|
import { TableAction } from '#/components/table-action';
|
|
|
|
|
|
import { $t } from '#/locales';
|
|
|
|
|
|
|
|
|
|
|
|
import {
|
2025-07-25 17:27:41 +08:00
|
|
|
|
addDeviceFormSchema,
|
2025-08-04 17:36:09 +08:00
|
|
|
|
batchAddDeviceFormSchema,
|
2025-08-01 17:36:42 +08:00
|
|
|
|
commandFormSchema,
|
2025-07-25 17:27:41 +08:00
|
|
|
|
editDeviceFormSchemaEdit,
|
2025-06-25 17:29:57 +08:00
|
|
|
|
querySchema,
|
|
|
|
|
|
tableSchema,
|
|
|
|
|
|
} from './schema';
|
|
|
|
|
|
|
|
|
|
|
|
defineOptions({
|
2025-07-25 17:27:41 +08:00
|
|
|
|
name: 'DeviceInfo',
|
2025-06-25 17:29:57 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
const formOptions: VbenFormProps = {
|
|
|
|
|
|
schema: querySchema.value,
|
|
|
|
|
|
};
|
|
|
|
|
|
const gridOptions: VxeGridProps<any> = {
|
|
|
|
|
|
checkboxConfig: {
|
|
|
|
|
|
highlight: true,
|
|
|
|
|
|
labelField: 'name',
|
|
|
|
|
|
},
|
|
|
|
|
|
columns: tableSchema.value,
|
|
|
|
|
|
height: 'auto',
|
|
|
|
|
|
keepSource: true,
|
|
|
|
|
|
pagerConfig: {},
|
|
|
|
|
|
toolbarConfig: {
|
|
|
|
|
|
custom: true,
|
|
|
|
|
|
},
|
|
|
|
|
|
customConfig: {
|
|
|
|
|
|
storage: true,
|
|
|
|
|
|
},
|
|
|
|
|
|
proxyConfig: {
|
|
|
|
|
|
ajax: {
|
|
|
|
|
|
query: async ({ page }, formValues) => {
|
2025-07-25 17:27:41 +08:00
|
|
|
|
const { data } = await postDeviceInfoPage({
|
2025-06-25 17:29:57 +08:00
|
|
|
|
body: {
|
|
|
|
|
|
pageIndex: page.currentPage,
|
|
|
|
|
|
pageSize: page.pageSize,
|
|
|
|
|
|
...formValues,
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
return data;
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const [Grid, gridApi] = useVbenVxeGrid({ formOptions, gridOptions });
|
|
|
|
|
|
|
|
|
|
|
|
const editRow: Record<string, any> = ref({});
|
2025-08-01 14:58:48 +08:00
|
|
|
|
const cacheRefreshLoading = ref(false);
|
|
|
|
|
|
const pageLoading = ref(false);
|
2025-08-01 17:36:42 +08:00
|
|
|
|
const commandRow: Record<string, any> = ref({});
|
2025-06-25 17:29:57 +08:00
|
|
|
|
const [UserModal, userModalApi] = useVbenModal({
|
|
|
|
|
|
draggable: true,
|
|
|
|
|
|
onConfirm: submit,
|
|
|
|
|
|
onBeforeClose: () => {
|
|
|
|
|
|
editRow.value = {};
|
|
|
|
|
|
return true;
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-08-01 17:36:42 +08:00
|
|
|
|
const [CommandModal, commandModalApi] = useVbenModal({
|
|
|
|
|
|
draggable: true,
|
|
|
|
|
|
onConfirm: submitCommand,
|
|
|
|
|
|
onBeforeClose: () => {
|
|
|
|
|
|
commandRow.value = {};
|
|
|
|
|
|
return true;
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-06-25 17:29:57 +08:00
|
|
|
|
const [AddForm, addFormApi] = useVbenForm({
|
|
|
|
|
|
// 默认展开
|
|
|
|
|
|
collapsed: false,
|
|
|
|
|
|
// 所有表单项共用,可单独在表单内覆盖
|
|
|
|
|
|
commonConfig: {
|
|
|
|
|
|
labelWidth: 110,
|
|
|
|
|
|
componentProps: {
|
|
|
|
|
|
class: 'w-4/5',
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
layout: 'horizontal',
|
2025-07-25 17:27:41 +08:00
|
|
|
|
schema: addDeviceFormSchema.value,
|
2025-06-25 17:29:57 +08:00
|
|
|
|
showCollapseButton: false,
|
|
|
|
|
|
showDefaultActions: false,
|
|
|
|
|
|
wrapperClass: 'grid-cols-2',
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const [EditForm, editFormApi] = useVbenForm({
|
|
|
|
|
|
// 默认展开
|
|
|
|
|
|
collapsed: false,
|
|
|
|
|
|
// 所有表单项共用,可单独在表单内覆盖
|
|
|
|
|
|
commonConfig: {
|
|
|
|
|
|
labelWidth: 110,
|
|
|
|
|
|
componentProps: {
|
|
|
|
|
|
class: 'w-4/5',
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
// 提交函数
|
|
|
|
|
|
layout: 'horizontal',
|
2025-07-25 17:27:41 +08:00
|
|
|
|
schema: editDeviceFormSchemaEdit.value,
|
2025-06-25 17:29:57 +08:00
|
|
|
|
showCollapseButton: false,
|
|
|
|
|
|
showDefaultActions: false,
|
|
|
|
|
|
wrapperClass: 'grid-cols-2',
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-08-01 17:36:42 +08:00
|
|
|
|
const [CommandForm, commandFormApi] = useVbenForm({
|
|
|
|
|
|
// 默认展开
|
|
|
|
|
|
collapsed: false,
|
|
|
|
|
|
// 所有表单项共用,可单独在表单内覆盖
|
|
|
|
|
|
commonConfig: {
|
|
|
|
|
|
labelWidth: 110,
|
|
|
|
|
|
componentProps: {
|
|
|
|
|
|
class: 'w-full',
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
layout: 'horizontal',
|
|
|
|
|
|
schema: commandFormSchema.value,
|
|
|
|
|
|
showCollapseButton: false,
|
|
|
|
|
|
showDefaultActions: false,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-08-04 17:36:09 +08:00
|
|
|
|
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',
|
2025-08-05 10:57:01 +08:00
|
|
|
|
// 添加响应式监听
|
|
|
|
|
|
autoSubmitOnEnter: false,
|
2025-08-04 17:36:09 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const [BatchAddModal, batchAddModalApi] = useVbenModal({
|
|
|
|
|
|
draggable: true,
|
|
|
|
|
|
onConfirm: submitBatchAdd,
|
|
|
|
|
|
onBeforeClose: () => {
|
2025-08-05 10:57:01 +08:00
|
|
|
|
batchAddFormApi.resetForm();
|
2025-08-04 17:36:09 +08:00
|
|
|
|
return true;
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-08-05 11:16:38 +08:00
|
|
|
|
// 获取批量添加模态框的状态
|
|
|
|
|
|
const batchAddModalState = batchAddModalApi.useStore();
|
|
|
|
|
|
|
2025-06-25 17:29:57 +08:00
|
|
|
|
// 新增和编辑提交的逻辑
|
|
|
|
|
|
async function submit() {
|
|
|
|
|
|
const isEdit = !!editRow.value.id;
|
|
|
|
|
|
const formApi = isEdit ? editFormApi : addFormApi;
|
2025-07-28 16:50:59 +08:00
|
|
|
|
const api = postAggregationDeviceCreateAsync; // 目前只有创建接口,编辑也使用创建接口
|
2025-06-25 17:29:57 +08:00
|
|
|
|
const { valid } = await formApi.validate();
|
|
|
|
|
|
if (!valid) return;
|
|
|
|
|
|
|
|
|
|
|
|
const formValues = await formApi.getValues();
|
2025-07-30 23:44:47 +08:00
|
|
|
|
|
2025-07-30 15:05:32 +08:00
|
|
|
|
// 根据平台类型处理数据
|
2025-07-30 23:44:47 +08:00
|
|
|
|
const processedFormValues = { ...formValues };
|
|
|
|
|
|
|
|
|
|
|
|
if (formValues.ioTPlatform === 2 || formValues.ioTPlatform === '2') {
|
2025-07-30 15:05:32 +08:00
|
|
|
|
// OneNET平台
|
|
|
|
|
|
processedFormValues.ioTPlatformAccountId = formValues.oneNETAccountId;
|
|
|
|
|
|
processedFormValues.ioTPlatformProductId = formValues.oneNETProductId;
|
|
|
|
|
|
// 清理不需要的字段
|
|
|
|
|
|
delete processedFormValues.oneNETAccountId;
|
|
|
|
|
|
delete processedFormValues.oneNETProductId;
|
|
|
|
|
|
delete processedFormValues.ctWingAccountId;
|
|
|
|
|
|
delete processedFormValues.ctWingProductId;
|
2025-07-30 23:44:47 +08:00
|
|
|
|
} else if (formValues.ioTPlatform === 1 || formValues.ioTPlatform === '1') {
|
2025-07-30 15:05:32 +08:00
|
|
|
|
// CTWing平台
|
|
|
|
|
|
processedFormValues.ioTPlatformAccountId = formValues.ctWingAccountId;
|
|
|
|
|
|
processedFormValues.ioTPlatformProductId = formValues.ctWingProductId;
|
|
|
|
|
|
// 清理不需要的字段
|
|
|
|
|
|
delete processedFormValues.ctWingAccountId;
|
|
|
|
|
|
delete processedFormValues.ctWingProductId;
|
|
|
|
|
|
delete processedFormValues.oneNETAccountId;
|
|
|
|
|
|
delete processedFormValues.oneNETProductId;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-25 17:29:57 +08:00
|
|
|
|
const fetchParams: any = isEdit
|
|
|
|
|
|
? {
|
2025-07-31 10:43:47 +08:00
|
|
|
|
id: editRow.value.id,
|
|
|
|
|
|
...processedFormValues,
|
|
|
|
|
|
}
|
2025-06-25 17:29:57 +08:00
|
|
|
|
: {
|
2025-07-31 10:43:47 +08:00
|
|
|
|
...processedFormValues,
|
|
|
|
|
|
};
|
2025-06-25 17:29:57 +08:00
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
userModalApi.setState({ loading: true, confirmLoading: true });
|
|
|
|
|
|
const resp = await api({ body: fetchParams });
|
|
|
|
|
|
if (resp.data) {
|
|
|
|
|
|
Message.success(
|
|
|
|
|
|
editRow.value.id ? $t('common.editSuccess') : $t('common.addSuccess'),
|
|
|
|
|
|
);
|
|
|
|
|
|
userModalApi.close();
|
2025-07-28 16:50:59 +08:00
|
|
|
|
editRow.value = {};
|
2025-06-25 17:29:57 +08:00
|
|
|
|
gridApi.reload();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Message.error(
|
|
|
|
|
|
editRow.value.id ? $t('common.editFail') : $t('common.addFail'),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2025-07-28 16:50:59 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('设备操作失败:', error);
|
|
|
|
|
|
Message.error(
|
|
|
|
|
|
editRow.value.id ? $t('common.editFail') : $t('common.addFail'),
|
|
|
|
|
|
);
|
2025-06-25 17:29:57 +08:00
|
|
|
|
} finally {
|
|
|
|
|
|
userModalApi.setState({ loading: false, confirmLoading: false });
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function onEdit(record: any) {
|
|
|
|
|
|
editRow.value = record;
|
|
|
|
|
|
userModalApi.open();
|
2025-07-30 23:44:47 +08:00
|
|
|
|
|
2025-07-30 15:05:32 +08:00
|
|
|
|
// 根据平台类型设置表单值
|
|
|
|
|
|
const formValues = { ...record };
|
2025-07-30 23:44:47 +08:00
|
|
|
|
|
2025-07-31 16:09:52 +08:00
|
|
|
|
// 确保ioTPlatform是字符串格式,因为ApiSelect组件的valueField是'key'
|
|
|
|
|
|
if (formValues.ioTPlatform !== undefined && formValues.ioTPlatform !== null) {
|
|
|
|
|
|
formValues.ioTPlatform = String(formValues.ioTPlatform);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-30 17:17:08 +08:00
|
|
|
|
if (record.ioTPlatform === 2 || record.ioTPlatform === '2') {
|
2025-07-30 15:05:32 +08:00
|
|
|
|
// OneNET平台
|
|
|
|
|
|
formValues.oneNETAccountId = record.ioTPlatformAccountId;
|
|
|
|
|
|
formValues.oneNETProductId = record.ioTPlatformProductId;
|
2025-07-30 17:17:08 +08:00
|
|
|
|
} else if (record.ioTPlatform === 1 || record.ioTPlatform === '1') {
|
2025-07-30 15:05:32 +08:00
|
|
|
|
// CTWing平台
|
|
|
|
|
|
formValues.ctWingAccountId = record.ioTPlatformAccountId;
|
|
|
|
|
|
formValues.ctWingProductId = record.ioTPlatformProductId;
|
|
|
|
|
|
}
|
2025-07-30 23:44:47 +08:00
|
|
|
|
|
2025-07-30 15:05:32 +08:00
|
|
|
|
editFormApi.setValues(formValues);
|
2025-06-25 17:29:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function onDel(row: any) {
|
|
|
|
|
|
Modal.confirm({
|
2025-07-28 16:50:59 +08:00
|
|
|
|
title: `${$t('common.confirmDelete')}${row.deviceName || row.deviceAddress} ?`,
|
2025-06-25 17:29:57 +08:00
|
|
|
|
onOk: async () => {
|
2025-07-28 16:50:59 +08:00
|
|
|
|
try {
|
2025-07-30 23:44:47 +08:00
|
|
|
|
const result = await postAggregationDeviceDeleteAsync({
|
|
|
|
|
|
body: { id: row.id },
|
|
|
|
|
|
});
|
2025-07-28 16:50:59 +08:00
|
|
|
|
if (result.data) {
|
|
|
|
|
|
gridApi.reload();
|
|
|
|
|
|
Message.success($t('common.deleteSuccess'));
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Message.error($t('common.deleteFail'));
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('删除设备失败:', error);
|
2025-06-25 17:29:57 +08:00
|
|
|
|
Message.error($t('common.deleteFail'));
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2025-08-01 15:40:26 +08:00
|
|
|
|
const toDeviceInfoData = (row: Record<string, any>) => {
|
2025-06-25 17:29:57 +08:00
|
|
|
|
// 或者使用编程式导航
|
|
|
|
|
|
router.push({
|
2025-08-01 15:40:26 +08:00
|
|
|
|
path: '/iotdbdatamanagement/deviceData',
|
2025-06-25 17:29:57 +08:00
|
|
|
|
query: {
|
2025-08-01 15:40:26 +08:00
|
|
|
|
DeviceAddress: row.deviceAddress,
|
2025-08-01 17:36:42 +08:00
|
|
|
|
IoTDataType: 'Data',
|
2025-06-25 17:29:57 +08:00
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
2025-08-01 16:01:58 +08:00
|
|
|
|
|
|
|
|
|
|
const toDeviceLog = (row: Record<string, any>) => {
|
|
|
|
|
|
// 根据平台类型跳转到对应的日志页面
|
|
|
|
|
|
if (row.ioTPlatform === 1 || row.ioTPlatform === '1') {
|
|
|
|
|
|
// CTWing平台
|
|
|
|
|
|
router.push({
|
|
|
|
|
|
path: '/iotdbdatamanagement/ctwingLog',
|
|
|
|
|
|
query: {
|
|
|
|
|
|
DeviceAddress: row.deviceAddress,
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
} else if (row.ioTPlatform === 2 || row.ioTPlatform === '2') {
|
|
|
|
|
|
// OneNET平台
|
|
|
|
|
|
router.push({
|
|
|
|
|
|
path: '/iotdbdatamanagement/onenetLog',
|
|
|
|
|
|
query: {
|
|
|
|
|
|
DeviceAddress: row.deviceAddress,
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2025-08-01 17:36:42 +08:00
|
|
|
|
|
|
|
|
|
|
const toTelemetryLog = (row: Record<string, any>) => {
|
|
|
|
|
|
// 跳转到遥测日志页面
|
|
|
|
|
|
router.push({
|
|
|
|
|
|
path: '/iotdbdatamanagement/telemetryLog',
|
|
|
|
|
|
query: {
|
|
|
|
|
|
DeviceAddress: row.deviceAddress,
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
2025-06-25 17:29:57 +08:00
|
|
|
|
const openAddModal = async () => {
|
|
|
|
|
|
editRow.value = {};
|
|
|
|
|
|
userModalApi.open();
|
|
|
|
|
|
};
|
2025-08-01 14:58:48 +08:00
|
|
|
|
|
2025-08-01 17:36:42 +08:00
|
|
|
|
const openCommandModal = (row: Record<string, any>) => {
|
|
|
|
|
|
commandRow.value = row;
|
|
|
|
|
|
commandModalApi.open();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 指令提交逻辑
|
|
|
|
|
|
async function submitCommand() {
|
|
|
|
|
|
const { valid } = await commandFormApi.validate();
|
|
|
|
|
|
if (!valid) return;
|
|
|
|
|
|
|
|
|
|
|
|
const formValues = await commandFormApi.getValues();
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
commandModalApi.setState({ loading: true, confirmLoading: true });
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: 调用指令接口
|
|
|
|
|
|
console.log('指令内容:', formValues.command);
|
|
|
|
|
|
console.log('设备信息:', commandRow.value);
|
|
|
|
|
|
|
|
|
|
|
|
Message.success($t('common.operationSuccess'));
|
|
|
|
|
|
commandModalApi.close();
|
|
|
|
|
|
commandRow.value = {};
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('指令发送失败:', error);
|
|
|
|
|
|
Message.error($t('common.operationFailed'));
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
commandModalApi.setState({ loading: false, confirmLoading: false });
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-04 17:36:09 +08:00
|
|
|
|
// 批量添加设备提交逻辑
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证设备地址格式(简单验证)
|
2025-08-05 10:57:01 +08:00
|
|
|
|
const invalidAddresses = addressList.filter(
|
|
|
|
|
|
(address: string) => !address || address.length < 3,
|
|
|
|
|
|
);
|
2025-08-04 17:36:09 +08:00
|
|
|
|
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,
|
|
|
|
|
|
};
|
2025-08-01 17:36:42 +08:00
|
|
|
|
|
2025-08-01 14:58:48 +08:00
|
|
|
|
try {
|
2025-08-04 17:36:09 +08:00
|
|
|
|
batchAddModalApi.setState({ loading: true, confirmLoading: true });
|
|
|
|
|
|
const resp = await postAggregationDeviceBatchCreateAsync({
|
|
|
|
|
|
body: batchCreateParams,
|
2025-08-01 14:58:48 +08:00
|
|
|
|
});
|
2025-08-04 17:36:09 +08:00
|
|
|
|
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 = () => {
|
2025-08-05 10:57:01 +08:00
|
|
|
|
console.log('打开批量添加模态框');
|
2025-08-04 17:36:09 +08:00
|
|
|
|
batchAddFormApi.resetForm();
|
|
|
|
|
|
batchAddModalApi.open();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-08-05 10:57:01 +08:00
|
|
|
|
// 批量添加地址行数
|
|
|
|
|
|
const addressLines = ref(0);
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当前地址行数的函数
|
|
|
|
|
|
const getAddressLines = () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const formValues = batchAddFormApi.getValues();
|
|
|
|
|
|
const addressList = formValues?.addressList;
|
|
|
|
|
|
if (!addressList || typeof addressList !== 'string') {
|
|
|
|
|
|
addressLines.value = 0;
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
const lines = addressList.split('\n').filter((line: string) => line.trim());
|
|
|
|
|
|
addressLines.value = lines.length;
|
|
|
|
|
|
return lines.length;
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
addressLines.value = 0;
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-08-05 11:16:38 +08:00
|
|
|
|
// 使用计算属性来实时计算行数
|
|
|
|
|
|
const computedAddressLines = computed(() => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const formValues = batchAddFormApi.getValues();
|
|
|
|
|
|
const addressList = formValues?.addressList;
|
|
|
|
|
|
if (!addressList || typeof addressList !== 'string') {
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
const lines = addressList.split('\n').filter((line: string) => line.trim());
|
|
|
|
|
|
return lines.length;
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 监听计算属性的变化,更新 addressLines
|
|
|
|
|
|
watch(computedAddressLines, (newValue) => {
|
|
|
|
|
|
addressLines.value = newValue;
|
|
|
|
|
|
}, { immediate: true });
|
2025-08-05 10:57:01 +08:00
|
|
|
|
|
2025-08-04 17:36:09 +08:00
|
|
|
|
// 缓存刷新按钮处理函数
|
|
|
|
|
|
const handleCacheRefresh = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
cacheRefreshLoading.value = true;
|
|
|
|
|
|
pageLoading.value = true;
|
|
|
|
|
|
const result = await postDeviceInfoCacheDeviceDataToRedis();
|
|
|
|
|
|
if (result.data) {
|
|
|
|
|
|
Message.success('缓存刷新成功');
|
|
|
|
|
|
gridApi.reload();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Message.error('缓存刷新失败');
|
|
|
|
|
|
}
|
2025-08-01 14:58:48 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('缓存刷新失败:', error);
|
2025-08-04 17:36:09 +08:00
|
|
|
|
Message.error('缓存刷新失败');
|
2025-08-01 14:58:48 +08:00
|
|
|
|
} finally {
|
|
|
|
|
|
cacheRefreshLoading.value = false;
|
|
|
|
|
|
pageLoading.value = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 工具栏按钮配置
|
|
|
|
|
|
const toolbarActions = computed(() => [
|
|
|
|
|
|
{
|
|
|
|
|
|
label: $t('common.add'),
|
|
|
|
|
|
type: 'primary',
|
|
|
|
|
|
icon: 'ant-design:plus-outlined',
|
|
|
|
|
|
onClick: openAddModal.bind(null),
|
|
|
|
|
|
auth: ['AbpIdentity.Users.Create'],
|
|
|
|
|
|
},
|
2025-08-04 17:36:09 +08:00
|
|
|
|
{
|
|
|
|
|
|
label: '批量添加',
|
|
|
|
|
|
type: 'primary',
|
|
|
|
|
|
icon: 'ant-design:plus-outlined',
|
|
|
|
|
|
onClick: openBatchAddModal.bind(null),
|
|
|
|
|
|
auth: ['AbpIdentity.Users.Create'],
|
|
|
|
|
|
},
|
2025-08-01 14:58:48 +08:00
|
|
|
|
{
|
|
|
|
|
|
label: cacheRefreshLoading.value
|
|
|
|
|
|
? $t('common.loading')
|
|
|
|
|
|
: $t('abp.IoTDBBase.CacheRefresh'),
|
2025-08-04 17:36:09 +08:00
|
|
|
|
type: 'default',
|
2025-08-01 14:58:48 +08:00
|
|
|
|
icon: cacheRefreshLoading.value
|
|
|
|
|
|
? 'ant-design:loading-outlined'
|
|
|
|
|
|
: 'ant-design:reload-outlined',
|
|
|
|
|
|
onClick: handleCacheRefresh,
|
|
|
|
|
|
disabled: cacheRefreshLoading.value,
|
|
|
|
|
|
style: {
|
|
|
|
|
|
backgroundColor: '#52c41a',
|
|
|
|
|
|
borderColor: '#52c41a',
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
]);
|
2025-06-25 17:29:57 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
|
<Page auto-content-height>
|
2025-08-01 14:58:48 +08:00
|
|
|
|
<Loading :loading="pageLoading" tip="缓存刷新中..." />
|
2025-06-25 17:29:57 +08:00
|
|
|
|
<Grid>
|
|
|
|
|
|
<template #toolbar-actions>
|
2025-08-01 14:58:48 +08:00
|
|
|
|
<TableAction :actions="toolbarActions" />
|
2025-06-25 17:29:57 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<template #isArchiveStatus="{ row }">
|
|
|
|
|
|
{{
|
|
|
|
|
|
row.archiveStatus ? $t('common.Issued') : $t('common.Undistributed')
|
|
|
|
|
|
}}
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<template #isTripState="{ row }">
|
|
|
|
|
|
{{ row.tripState ? $t('common.SwitchOff') : $t('common.Closing') }}
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<template #isHaveValve="{ row }">
|
2025-07-31 10:43:47 +08:00
|
|
|
|
<component :is="h(Tag, { color: row.haveValve ? 'green' : 'red' }, () =>
|
|
|
|
|
|
row.haveValve ? $t('common.yes') : $t('common.no'),
|
|
|
|
|
|
)
|
|
|
|
|
|
" />
|
2025-06-25 17:29:57 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
<template #isSelfDevelop="{ row }">
|
2025-07-31 10:43:47 +08:00
|
|
|
|
<component :is="h(Tag, { color: row.selfDevelop ? 'green' : 'red' }, () =>
|
|
|
|
|
|
row.selfDevelop ? $t('common.yes') : $t('common.no'),
|
|
|
|
|
|
)
|
|
|
|
|
|
" />
|
2025-06-25 17:29:57 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
<template #isDynamicPassword="{ row }">
|
2025-07-31 10:43:47 +08:00
|
|
|
|
<component :is="h(Tag, { color: row.dynamicPassword ? 'green' : 'red' }, () =>
|
|
|
|
|
|
row.dynamicPassword ? $t('common.yes') : $t('common.no'),
|
|
|
|
|
|
)
|
|
|
|
|
|
" />
|
2025-06-25 17:29:57 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
<template #isEnable="{ row }">
|
2025-07-31 10:43:47 +08:00
|
|
|
|
<component :is="h(Tag, { color: row.enabled ? 'green' : 'red' }, () =>
|
|
|
|
|
|
row.enabled ? $t('common.yes') : $t('common.no'),
|
|
|
|
|
|
)
|
|
|
|
|
|
" />
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<template #ioTPlatformName="{ row }">
|
|
|
|
|
|
<span :style="{
|
|
|
|
|
|
color:
|
|
|
|
|
|
row.ioTPlatform === 2 || row.ioTPlatform === '2'
|
|
|
|
|
|
? '#0B34BE'
|
|
|
|
|
|
: '#048CD1',
|
|
|
|
|
|
fontWeight: 'bold',
|
|
|
|
|
|
}">
|
|
|
|
|
|
{{ row.ioTPlatformName }}
|
|
|
|
|
|
</span>
|
2025-06-25 17:29:57 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
2025-08-01 14:58:48 +08:00
|
|
|
|
<template #action="{ row }">
|
2025-08-01 17:36:42 +08:00
|
|
|
|
<div style="display: flex; gap: 8px; align-items: center">
|
|
|
|
|
|
<Button size="small" type="link" @click="onEdit.bind(null, row)()">
|
|
|
|
|
|
{{ $t('common.edit') }}
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
<Button size="small" type="link" @click="toDeviceInfoData.bind(null, row)()">
|
|
|
|
|
|
{{ $t('abp.deviceInfos.viewData') }}
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
<Button size="small" type="link" @click="openCommandModal.bind(null, row)()">
|
|
|
|
|
|
{{ $t('abp.IoTDBBase.Command') }}
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
<Popover trigger="hover" placement="bottomRight" :overlay-style="{ minWidth: '120px' }">
|
|
|
|
|
|
<template #content>
|
|
|
|
|
|
<div style="display: flex; flex-direction: column; gap: 4px">
|
|
|
|
|
|
<Button type="text" size="small" @click="toDeviceLog.bind(null, row)()"
|
2025-08-05 10:57:01 +08:00
|
|
|
|
style="padding: 4px 8px; text-align: left">
|
2025-08-01 17:36:42 +08:00
|
|
|
|
{{ $t('abp.IoTDBBase.PlatformLog') }}
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
<Button type="text" size="small" @click="toTelemetryLog.bind(null, row)()"
|
2025-08-05 10:57:01 +08:00
|
|
|
|
style="padding: 4px 8px; text-align: left">
|
2025-08-01 17:36:42 +08:00
|
|
|
|
{{ $t('abp.IoTDBBase.TelemetryLog') }}
|
|
|
|
|
|
</Button>
|
2025-08-04 17:36:09 +08:00
|
|
|
|
<Button type="text" size="small" @click="onDel.bind(null, row)()"
|
2025-08-05 10:57:01 +08:00
|
|
|
|
style="padding: 4px 8px; color: #ff4d4f; text-align: left">
|
2025-08-01 17:36:42 +08:00
|
|
|
|
{{ $t('common.delete') }}
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<Button size="small" type="link">
|
|
|
|
|
|
<template #icon>
|
|
|
|
|
|
<Icon icon="ant-design:more-outlined" />
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</Popover>
|
|
|
|
|
|
</div>
|
2025-08-01 14:58:48 +08:00
|
|
|
|
</template>
|
2025-06-25 17:29:57 +08:00
|
|
|
|
</Grid>
|
2025-07-31 10:43:47 +08:00
|
|
|
|
<UserModal :title="editRow.id ? $t('common.edit') : $t('common.add')" class="w-[800px]">
|
2025-06-25 17:29:57 +08:00
|
|
|
|
<component :is="editRow.id ? EditForm : AddForm" />
|
|
|
|
|
|
</UserModal>
|
2025-08-01 17:36:42 +08:00
|
|
|
|
<CommandModal :title="$t('abp.IoTDBBase.Command')" class="w-[600px]">
|
|
|
|
|
|
<CommandForm />
|
|
|
|
|
|
</CommandModal>
|
2025-08-04 17:36:09 +08:00
|
|
|
|
<BatchAddModal title="批量添加设备" class="w-[800px]">
|
|
|
|
|
|
<BatchAddForm />
|
2025-08-05 10:57:01 +08:00
|
|
|
|
<template #footer>
|
|
|
|
|
|
<div class="flex w-full items-center justify-between">
|
|
|
|
|
|
<div class="text-sm text-gray-500">
|
|
|
|
|
|
<span v-if="addressLines > 0">
|
|
|
|
|
|
共 {{ addressLines }} 行设备地址
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
2025-08-05 11:16:38 +08:00
|
|
|
|
<div class="flex gap-2">
|
|
|
|
|
|
<Button @click="batchAddModalApi.close()">
|
|
|
|
|
|
{{ $t('common.cancel') }}
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
<Button type="primary" :loading="batchAddModalState?.confirmLoading" @click="submitBatchAdd">
|
|
|
|
|
|
{{ $t('common.confirm') }}
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</div>
|
2025-08-05 10:57:01 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
2025-08-04 17:36:09 +08:00
|
|
|
|
</BatchAddModal>
|
2025-06-25 17:29:57 +08:00
|
|
|
|
</Page>
|
|
|
|
|
|
</template>
|