{{ device.deviceName }}
-
@@ -72,8 +77,8 @@ function goToProductDetail(productId: number | undefined) {
{{ product.name }}
@@ -90,8 +95,5 @@ function goToProductDetail(productId: number | undefined) {
-
-
-
diff --git a/apps/web-antd/src/views/iot/device/device/modules/detail/device-details-info.vue b/apps/web-antd/src/views/iot/device/device/modules/detail/modules/info.vue
similarity index 80%
rename from apps/web-antd/src/views/iot/device/device/modules/detail/device-details-info.vue
rename to apps/web-antd/src/views/iot/device/device/modules/detail/modules/info.vue
index fc7f056ea..a1b5f6406 100644
--- a/apps/web-antd/src/views/iot/device/device/modules/detail/device-details-info.vue
+++ b/apps/web-antd/src/views/iot/device/device/modules/detail/modules/info.vue
@@ -1,5 +1,4 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ item.deviceName }}
-
-
-
-
-
-
- 设备类型
-
- {{
- getDictLabel(
- DICT_TYPE.IOT_PRODUCT_DEVICE_TYPE,
- item.deviceType,
- )
- }}
-
-
-
- Deviceid
-
- {{ item.Deviceid || item.id }}
-
-
-
-
-
-
-
-
-
-
emit('delete', item)"
- >
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/apps/web-antd/src/views/iot/device/device/modules/device-import-form.vue b/apps/web-antd/src/views/iot/device/device/modules/device-import-form.vue
deleted file mode 100644
index 710971ce1..000000000
--- a/apps/web-antd/src/views/iot/device/device/modules/device-import-form.vue
+++ /dev/null
@@ -1,133 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/apps/web-antd/src/views/iot/device/device/modules/device-form.vue b/apps/web-antd/src/views/iot/device/device/modules/form.vue
similarity index 73%
rename from apps/web-antd/src/views/iot/device/device/modules/device-form.vue
rename to apps/web-antd/src/views/iot/device/device/modules/form.vue
index 39fe16a99..2994e8d00 100644
--- a/apps/web-antd/src/views/iot/device/device/modules/device-form.vue
+++ b/apps/web-antd/src/views/iot/device/device/modules/form.vue
@@ -3,11 +3,16 @@ import type { IotDeviceApi } from '#/api/iot/device/device';
import { computed, ref } from 'vue';
-import { useVbenForm, useVbenModal } from '@vben/common-ui';
+import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
-import { createDevice, getDevice, updateDevice } from '#/api/iot/device/device';
+import { useVbenForm } from '#/adapter/form';
+import {
+ createDevice,
+ getDevice,
+ updateDevice,
+} from '#/api/iot/device/device';
import { $t } from '#/locales';
import { useFormSchema } from '../data';
@@ -15,9 +20,11 @@ import { useFormSchema } from '../data';
defineOptions({ name: 'IoTDeviceForm' });
const emit = defineEmits(['success']);
-const formData = ref
();
+const formData = ref();
const getTitle = computed(() => {
- return formData.value?.id ? '编辑设备' : '新增设备';
+ return formData.value?.id
+ ? $t('ui.actionTitle.edit', ['设备'])
+ : $t('ui.actionTitle.create', ['设备']);
});
const [Form, formApi] = useVbenForm({
@@ -33,6 +40,7 @@ const [Form, formApi] = useVbenForm({
});
const [Modal, modalApi] = useVbenModal({
+ /** 提交表单 */
async onConfirm() {
const { valid } = await formApi.validate();
if (!valid) {
@@ -43,7 +51,6 @@ const [Modal, modalApi] = useVbenModal({
const data = (await formApi.getValues()) as IotDeviceApi.Device;
try {
await (formData.value?.id ? updateDevice(data) : createDevice(data));
- // 关闭并提示
await modalApi.close();
emit('success');
message.success($t('ui.actionMessage.operationSuccess'));
@@ -51,20 +58,23 @@ const [Modal, modalApi] = useVbenModal({
modalApi.unlock();
}
},
+ /** 弹窗打开/关闭 */
async onOpenChange(isOpen: boolean) {
if (!isOpen) {
formData.value = undefined;
return;
}
// 加载数据
- const data = modalApi.getData();
+ const data = modalApi.getData();
if (!data || !data.id) {
+ // 新增模式:设置默认值(如果需要)
+ formData.value = undefined;
return;
}
+ // 编辑模式:加载数据
modalApi.lock();
try {
formData.value = await getDevice(data.id);
- // 设置到 values
await formApi.setValues(formData.value);
} finally {
modalApi.unlock();
diff --git a/apps/web-antd/src/views/iot/device/device/modules/device-group-form.vue b/apps/web-antd/src/views/iot/device/device/modules/group-form.vue
similarity index 91%
rename from apps/web-antd/src/views/iot/device/device/modules/device-group-form.vue
rename to apps/web-antd/src/views/iot/device/device/modules/group-form.vue
index fa85a0ffb..86b37032a 100644
--- a/apps/web-antd/src/views/iot/device/device/modules/device-group-form.vue
+++ b/apps/web-antd/src/views/iot/device/device/modules/group-form.vue
@@ -1,10 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/web-antd/src/views/iot/product/product/index.vue b/apps/web-antd/src/views/iot/product/product/index.vue
index 3aa14191d..421514c36 100644
--- a/apps/web-antd/src/views/iot/product/product/index.vue
+++ b/apps/web-antd/src/views/iot/product/product/index.vue
@@ -12,6 +12,8 @@ import { downloadFileFromBlobPart } from '@vben/utils';
import { Button, Card, Input, message, Space } from 'ant-design-vue';
+import { ProductStatusEnum } from '@vben/constants';
+
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { getSimpleProductCategoryList } from '#/api/iot/product/category';
import {
@@ -253,6 +255,7 @@ onMounted(() => {
type: 'link',
danger: true,
icon: ACTION_ICON.DELETE,
+ disabled: row.status === ProductStatusEnum.PUBLISHED,
popConfirm: {
title: `确认删除产品 ${row.name} 吗?`,
confirm: handleDelete.bind(null, row),
diff --git a/apps/web-antd/src/views/iot/product/product/modules/detail/modules/header.vue b/apps/web-antd/src/views/iot/product/product/modules/detail/modules/header.vue
index ef31b79de..62df0cae1 100644
--- a/apps/web-antd/src/views/iot/product/product/modules/detail/modules/header.vue
+++ b/apps/web-antd/src/views/iot/product/product/modules/detail/modules/header.vue
@@ -7,10 +7,9 @@ import { useVbenModal } from '@vben/common-ui';
import { Button, Card, Descriptions, message, Modal } from 'ant-design-vue';
-import {
- ProductStatusEnum,
- updateProductStatus,
-} from '#/api/iot/product/product';
+import { ProductStatusEnum } from '@vben/constants';
+
+import { updateProductStatus } from '#/api/iot/product/product';
import Form from '../../form.vue';
diff --git a/apps/web-antd/src/views/iot/product/product/modules/detail/modules/info.vue b/apps/web-antd/src/views/iot/product/product/modules/detail/modules/info.vue
index 2693fff49..3d0ae5b99 100644
--- a/apps/web-antd/src/views/iot/product/product/modules/detail/modules/info.vue
+++ b/apps/web-antd/src/views/iot/product/product/modules/detail/modules/info.vue
@@ -5,7 +5,7 @@ import { DICT_TYPE } from '@vben/constants';
import { Card, Descriptions } from 'ant-design-vue';
-import { DeviceTypeEnum } from '#/api/iot/product/product';
+import { DeviceTypeEnum } from '@vben/constants';
import { DictTag } from '#/components/dict-tag';
interface Props {
diff --git a/packages/constants/src/biz-iot-enum.ts b/packages/constants/src/biz-iot-enum.ts
index ad2f3bd5a..f494a9a78 100644
--- a/packages/constants/src/biz-iot-enum.ts
+++ b/packages/constants/src/biz-iot-enum.ts
@@ -1 +1,43 @@
-// TODO @haohao:枚举可以放到这里;
+// ========== IOT - 设备模块 ==========
+/**
+ * 设备状态枚举
+ */
+export const DeviceStateEnum = {
+ INACTIVE: 0, // 未激活
+ OFFLINE: 2, // 离线
+ ONLINE: 1, // 在线
+} as const;
+
+// ========== IOT - 产品模块 ==========
+/**
+ * 产品设备类型枚举
+ */
+export const DeviceTypeEnum = {
+ DEVICE: 0, // 直连设备
+ GATEWAY: 2, // 网关设备
+ GATEWAY_SUB: 1, // 网关子设备
+} as const;
+
+/**
+ * 产品状态枚举
+ */
+export const ProductStatusEnum = {
+ UNPUBLISHED: 0, // 开发中
+ PUBLISHED: 1, // 已发布
+} as const;
+
+/**
+ * 产品定位类型枚举
+ */
+export const LocationTypeEnum = {
+ IP: 1, // IP 定位
+ MANUAL: 3, // 手动定位
+ MODULE: 2, // 设备定位
+} as const;
+
+/**
+ * 数据格式(编解码器类型)枚举
+ */
+export const CodecTypeEnum = {
+ ALINK: 'Alink', // 阿里云 Alink 协议
+} as const;
From 7366b948a3751c7eee8122432f537e5c4aa27cef Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Sun, 7 Dec 2025 12:26:03 +0800
Subject: [PATCH 4/7] =?UTF-8?q?fix:=20=E3=80=90bpm=E3=80=91bpmn=E8=AE=BE?=
=?UTF-8?q?=E8=AE=A1=E5=99=A8:=20=E7=BB=84=E4=BB=B6=E9=83=A8=E5=88=86?=
=?UTF-8?q?=E5=B1=9E=E6=80=A7=E7=AC=AC=E4=B8=80=E6=AC=A1=E5=A4=B1=E5=8E=BB?=
=?UTF-8?q?=E7=84=A6=E7=82=B9=E4=B8=A2=E5=A4=B1=E6=95=B0=E6=8D=AE=E9=97=AE?=
=?UTF-8?q?=E9=A2=98=20#204=20=E3=80=90=E5=90=8C=E6=AD=A5=E8=87=AA=20vue3?=
=?UTF-8?q?=20+=20element-plus=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../penal/listeners/ElementListeners.vue | 36 +++++++---
.../penal/listeners/UserTaskListeners.vue | 36 +++++++---
.../penal/properties/ElementProperties.vue | 65 ++++++++++---------
.../bpmn-process-designer/package/utils.ts | 5 +-
4 files changed, 91 insertions(+), 51 deletions(-)
diff --git a/apps/web-antd/src/views/bpm/components/bpmn-process-designer/package/penal/listeners/ElementListeners.vue b/apps/web-antd/src/views/bpm/components/bpmn-process-designer/package/penal/listeners/ElementListeners.vue
index e2b88ffdb..8e68131e9 100644
--- a/apps/web-antd/src/views/bpm/components/bpmn-process-designer/package/penal/listeners/ElementListeners.vue
+++ b/apps/web-antd/src/views/bpm/components/bpmn-process-designer/package/penal/listeners/ElementListeners.vue
@@ -52,7 +52,6 @@ const editingListenerIndex = ref(-1); // 监听器所在下标,-1 为新增
const editingListenerFieldIndex = ref(-1); // 字段所在下标,-1 为新增
const listenerTypeObject = ref(listenerType);
const fieldTypeObject = ref(fieldType);
-const bpmnElement = ref();
const otherExtensionList = ref();
const bpmnElementListeners = ref();
const listenerFormRef = ref();
@@ -60,13 +59,19 @@ const listenerFieldFormRef = ref();
const bpmnInstances = () => (window as any)?.bpmnInstances;
const resetListenersList = () => {
- bpmnElement.value = bpmnInstances().bpmnElement;
+ const instances = bpmnInstances();
+ if (!instances || !instances.bpmnElement) return;
+
+ // 直接使用原始BPMN元素,避免Vue响应式代理问题
+ const bpmnElement = instances.bpmnElement;
+ const businessObject = bpmnElement.businessObject;
+
otherExtensionList.value =
- bpmnElement.value.businessObject?.extensionElements?.values?.filter(
+ businessObject?.extensionElements?.values?.filter(
(ex: any) => ex.$type !== `${prefix}:ExecutionListener`,
) ?? []; // 保留非监听器类型的扩展属性,避免移除监听器时清空其他配置(如审批人等)。相关案例:https://gitee.com/yudaocode/yudao-ui-admin-vue3/issues/ICMSYC
bpmnElementListeners.value =
- bpmnElement.value.businessObject?.extensionElements?.values?.filter(
+ businessObject?.extensionElements?.values?.filter(
(ex: any) => ex.$type === `${prefix}:ExecutionListener`,
) ?? [];
elementListenersList.value = bpmnElementListeners.value.map((listener: any) =>
@@ -162,9 +167,12 @@ const removeListener = (index: number) => {
okText: '确 认',
cancelText: '取 消',
onOk() {
+ const instances = bpmnInstances();
+ if (!instances || !instances.bpmnElement) return;
+
bpmnElementListeners.value.splice(index, 1);
elementListenersList.value.splice(index, 1);
- updateElementExtensions(bpmnElement.value, [
+ updateElementExtensions(instances.bpmnElement, [
...otherExtensionList.value,
...bpmnElementListeners.value,
]);
@@ -179,11 +187,17 @@ const saveListenerConfig = async () => {
// debugger
const validateStatus = await listenerFormRef.value.validate();
if (!validateStatus) return; // 验证不通过直接返回
+
+ const instances = bpmnInstances();
+ if (!instances || !instances.bpmnElement) return;
+
+ const bpmnElement = instances.bpmnElement;
const listenerObject = createListenerObject(
listenerForm.value,
false,
prefix,
);
+
if (editingListenerIndex.value === -1) {
bpmnElementListeners.value.push(listenerObject);
elementListenersList.value.push(listenerForm.value);
@@ -201,10 +215,10 @@ const saveListenerConfig = async () => {
}
// 保存其他配置
otherExtensionList.value =
- bpmnElement.value.businessObject?.extensionElements?.values?.filter(
+ bpmnElement.businessObject?.extensionElements?.values?.filter(
(ex: any) => ex.$type !== `${prefix}:ExecutionListener`,
) ?? [];
- updateElementExtensions(bpmnElement.value, [
+ updateElementExtensions(bpmnElement, [
...otherExtensionList.value,
...bpmnElementListeners.value,
]);
@@ -219,6 +233,10 @@ const openProcessListenerDialog = async () => {
processListenerDialogRef.value.open('execution');
};
const selectProcessListener = (listener: any) => {
+ const instances = bpmnInstances();
+ if (!instances || !instances.bpmnElement) return;
+
+ const bpmnElement = instances.bpmnElement;
const listenerForm = initListenerForm2(listener);
const listenerObject = createListenerObject(listenerForm, false, prefix);
bpmnElementListeners.value.push(listenerObject);
@@ -226,10 +244,10 @@ const selectProcessListener = (listener: any) => {
// 保存其他配置
otherExtensionList.value =
- bpmnElement.value.businessObject?.extensionElements?.values?.filter(
+ bpmnElement.businessObject?.extensionElements?.values?.filter(
(ex: any) => ex.$type !== `${prefix}:ExecutionListener`,
) ?? [];
- updateElementExtensions(bpmnElement.value, [
+ updateElementExtensions(bpmnElement, [
...otherExtensionList.value,
...bpmnElementListeners.value,
]);
diff --git a/apps/web-antd/src/views/bpm/components/bpmn-process-designer/package/penal/listeners/UserTaskListeners.vue b/apps/web-antd/src/views/bpm/components/bpmn-process-designer/package/penal/listeners/UserTaskListeners.vue
index f0b48f642..2788ef29c 100644
--- a/apps/web-antd/src/views/bpm/components/bpmn-process-designer/package/penal/listeners/UserTaskListeners.vue
+++ b/apps/web-antd/src/views/bpm/components/bpmn-process-designer/package/penal/listeners/UserTaskListeners.vue
@@ -48,7 +48,6 @@ const fieldsListOfListener = ref([]);
const editingListenerIndex = ref(-1);
const editingListenerFieldIndex = ref(-1);
const listenerFieldForm = ref({});
-const bpmnElement = ref();
const bpmnElementListeners = ref([]);
const otherExtensionList = ref([]);
const listenerFormRef = ref({});
@@ -57,13 +56,19 @@ const listenerFieldFormRef = ref({});
const bpmnInstances = () => (window as any)?.bpmnInstances;
const resetListenersList = () => {
- bpmnElement.value = bpmnInstances()?.bpmnElement;
+ const instances = bpmnInstances();
+ if (!instances || !instances.bpmnElement) return;
+
+ // 直接使用原始BPMN元素,避免Vue响应式代理问题
+ const bpmnElement = instances.bpmnElement;
+ const businessObject = bpmnElement.businessObject;
+
otherExtensionList.value =
- bpmnElement.value.businessObject?.extensionElements?.values?.filter(
+ businessObject?.extensionElements?.values?.filter(
(ex: any) => ex.$type !== `${prefix}:TaskListener`,
) ?? [];
bpmnElementListeners.value =
- bpmnElement.value.businessObject?.extensionElements?.values?.filter(
+ businessObject?.extensionElements?.values?.filter(
(ex: any) => ex.$type === `${prefix}:TaskListener`,
) ?? [];
elementListenersList.value = bpmnElementListeners.value.map((listener) =>
@@ -99,9 +104,12 @@ const removeListener = (_: any, index: number) => {
title: '提示',
content: '确认移除该监听器吗?',
}).then(() => {
+ const instances = bpmnInstances();
+ if (!instances || !instances.bpmnElement) return;
+
bpmnElementListeners.value.splice(index, 1);
elementListenersList.value.splice(index, 1);
- updateElementExtensions(bpmnElement.value, [
+ updateElementExtensions(instances.bpmnElement, [
...otherExtensionList.value,
...bpmnElementListeners.value,
]);
@@ -114,7 +122,13 @@ async function saveListenerConfig() {
} catch {
return;
}
+
+ const instances = bpmnInstances();
+ if (!instances || !instances.bpmnElement) return;
+
+ const bpmnElement = instances.bpmnElement;
const listenerObject = createListenerObject(listenerForm.value, true, prefix);
+
if (editingListenerIndex.value === -1) {
bpmnElementListeners.value.push(listenerObject);
elementListenersList.value.push(listenerForm.value);
@@ -131,10 +145,10 @@ async function saveListenerConfig() {
);
}
otherExtensionList.value =
- bpmnElement.value.businessObject?.extensionElements?.values?.filter(
+ bpmnElement.businessObject?.extensionElements?.values?.filter(
(ex: any) => ex.$type !== `${prefix}:TaskListener`,
) ?? [];
- updateElementExtensions(bpmnElement.value, [
+ updateElementExtensions(bpmnElement, [
...otherExtensionList.value,
...bpmnElementListeners.value,
]);
@@ -229,17 +243,21 @@ const openProcessListenerDialog = async () => {
processListenerDialogRef.value.open('task');
};
const selectProcessListener = (listener: any) => {
+ const instances = bpmnInstances();
+ if (!instances || !instances.bpmnElement) return;
+
+ const bpmnElement = instances.bpmnElement;
const listenerForm = initListenerForm2(listener);
const listenerObject = createListenerObject(listenerForm, true, prefix);
bpmnElementListeners.value.push(listenerObject);
elementListenersList.value.push(listenerForm);
otherExtensionList.value =
- bpmnElement.value.businessObject?.extensionElements?.values?.filter(
+ bpmnElement.businessObject?.extensionElements?.values?.filter(
(ex: any) => ex.$type !== `${prefix}:TaskListener`,
) ?? [];
updateElementExtensions(
- bpmnElement.value,
+ bpmnElement,
otherExtensionList.value?.concat(bpmnElementListeners.value),
);
};
diff --git a/apps/web-antd/src/views/bpm/components/bpmn-process-designer/package/penal/properties/ElementProperties.vue b/apps/web-antd/src/views/bpm/components/bpmn-process-designer/package/penal/properties/ElementProperties.vue
index 26a4267f6..cc96afa68 100644
--- a/apps/web-antd/src/views/bpm/components/bpmn-process-designer/package/penal/properties/ElementProperties.vue
+++ b/apps/web-antd/src/views/bpm/components/bpmn-process-designer/package/penal/properties/ElementProperties.vue
@@ -1,5 +1,5 @@