fix: iot 二次确认统一改用 popconfirm 模式(P1)

- 设备详情「配置推送」按钮包 Popconfirm / ElPopconfirm,防误下发
- 场景联动列表 TableAction 启用 / 停用项改用 popConfirm 配置
- 产品详情头部「发布 / 撤销发布 / 同步物模型表结构」三处按钮同步切换
- 移除命令式 Modal.confirm / ElMessageBox.confirm,与 system / iot 现有惯例一致
- 顺带消除 ele 端 ElMessageBox.confirm 取消未 catch 的未处理 promise
pull/345/head
YunaiV 2026-05-21 12:44:12 +08:00
parent 751ba2c782
commit 1afa70bb53
6 changed files with 94 additions and 85 deletions

View File

@ -6,7 +6,7 @@ import { computed, ref, watchEffect } from 'vue';
import { IotDeviceMessageMethodEnum } from '@vben/constants';
import { Alert, Button, message, Textarea } from 'ant-design-vue';
import { Alert, Button, message, Popconfirm, Textarea } from 'ant-design-vue';
import { sendDeviceMessage, updateDevice } from '#/api/iot/device/device';
@ -160,14 +160,13 @@ async function updateDeviceConfig() {
保存
</Button>
<Button v-else @click="handleEdit"></Button>
<Button
<Popconfirm
v-if="!isEditing"
:loading="pushLoading"
type="primary"
@click="handleConfigPush"
title="确定要推送配置到设备吗?此操作将远程更新设备配置。"
@confirm="handleConfigPush"
>
配置推送
</Button>
<Button :loading="pushLoading" type="primary"> 配置推送 </Button>
</Popconfirm>
</div>
</div>
</template>

View File

@ -7,7 +7,13 @@ import { useAccess } from '@vben/access';
import { useVbenModal } from '@vben/common-ui';
import { ProductStatusEnum } from '@vben/constants';
import { Button, Card, Descriptions, message, Modal } from 'ant-design-vue';
import {
Button,
Card,
Descriptions,
message,
Popconfirm,
} from 'ant-design-vue';
import {
syncProductPropertyTable,
@ -61,41 +67,23 @@ function openEditForm(row: IotProductApi.Product) {
}
/** 发布产品 */
function handlePublish(product: IotProductApi.Product) {
Modal.confirm({
title: '确认发布',
content: `确认要发布产品「${product.name}」吗?`,
async onOk() {
await updateProductStatus(product.id!, ProductStatusEnum.PUBLISHED);
message.success('发布成功');
emit('refresh');
},
});
async function handlePublish(product: IotProductApi.Product) {
await updateProductStatus(product.id!, ProductStatusEnum.PUBLISHED);
message.success('发布成功');
emit('refresh');
}
/** 撤销发布 */
function handleUnpublish(product: IotProductApi.Product) {
Modal.confirm({
title: '确认撤销发布',
content: `确认要撤销发布产品「${product.name}」吗?`,
async onOk() {
await updateProductStatus(product.id!, ProductStatusEnum.UNPUBLISHED);
message.success('撤销发布成功');
emit('refresh');
},
});
async function handleUnpublish(product: IotProductApi.Product) {
await updateProductStatus(product.id!, ProductStatusEnum.UNPUBLISHED);
message.success('撤销发布成功');
emit('refresh');
}
/** 同步物模型超级表结构 */
function handleSyncPropertyTable(product: IotProductApi.Product) {
Modal.confirm({
title: '确认同步',
content: `确认要同步产品「${product.name}」的物模型超级表结构吗?`,
async onOk() {
await syncProductPropertyTable(product.id!);
message.success('同步成功');
},
});
async function handleSyncPropertyTable(product: IotProductApi.Product) {
await syncProductPropertyTable(product.id!);
message.success('同步成功');
}
</script>
@ -115,32 +103,33 @@ function handleSyncPropertyTable(product: IotProductApi.Product) {
>
编辑
</Button>
<Button
<Popconfirm
v-if="
product.status === ProductStatusEnum.UNPUBLISHED &&
hasAccessByCodes(['iot:product:update'])
"
type="primary"
@click="handlePublish(product)"
:title="`确认要发布产品「${product.name}」吗?`"
@confirm="handlePublish(product)"
>
发布
</Button>
<Button
<Button type="primary">发布</Button>
</Popconfirm>
<Popconfirm
v-if="
product.status === ProductStatusEnum.PUBLISHED &&
hasAccessByCodes(['iot:product:update'])
"
danger
@click="handleUnpublish(product)"
:title="`确认要撤销发布产品「${product.name}」吗?`"
@confirm="handleUnpublish(product)"
>
撤销发布
</Button>
<Button
<Button danger>撤销发布</Button>
</Popconfirm>
<Popconfirm
v-if="hasAccessByCodes(['iot:product:update'])"
@click="handleSyncPropertyTable(product)"
:title="`确认要同步产品「${product.name}」的物模型超级表结构吗?`"
@confirm="handleSyncPropertyTable(product)"
>
同步物模型表结构
</Button>
<Button>同步物模型表结构</Button>
</Popconfirm>
</div>
</div>

View File

@ -372,7 +372,10 @@ const [Grid, gridApi] = useVbenVxeGrid({
row.status === CommonStatusEnum.ENABLE
? 'ant-design:stop-outlined'
: 'ant-design:check-circle-outlined',
onClick: handleToggleStatus.bind(null, row),
popConfirm: {
title: `确认${row.status === CommonStatusEnum.ENABLE ? '停用' : '启用'}场景规则「${row.name}」吗?`,
confirm: handleToggleStatus.bind(null, row),
},
},
{
label: $t('common.edit'),

View File

@ -6,7 +6,13 @@ import { computed, ref, watchEffect } from 'vue';
import { IotDeviceMessageMethodEnum } from '@vben/constants';
import { ElAlert, ElButton, ElInput, ElMessage } from 'element-plus';
import {
ElAlert,
ElButton,
ElInput,
ElMessage,
ElPopconfirm,
} from 'element-plus';
import { sendDeviceMessage, updateDevice } from '#/api/iot/device/device';
@ -162,14 +168,17 @@ async function updateDeviceConfig() {
保存
</ElButton>
<ElButton v-else @click="handleEdit"></ElButton>
<ElButton
<ElPopconfirm
v-if="!isEditing"
:loading="pushLoading"
type="primary"
@click="handleConfigPush"
title="确定要推送配置到设备吗?此操作将远程更新设备配置。"
@confirm="handleConfigPush"
>
配置推送
</ElButton>
<template #reference>
<ElButton :loading="pushLoading" type="primary">
配置推送
</ElButton>
</template>
</ElPopconfirm>
</div>
</div>
</template>

View File

@ -13,7 +13,7 @@ import {
ElDescriptions,
ElDescriptionsItem,
ElMessage,
ElMessageBox,
ElPopconfirm,
} from 'element-plus';
import {
@ -69,7 +69,6 @@ function openEditForm(row: IotProductApi.Product) {
/** 发布产品 */
async function handlePublish(product: IotProductApi.Product) {
await ElMessageBox.confirm(`确认要发布产品「${product.name}」吗?`, '确认发布');
await updateProductStatus(product.id!, ProductStatusEnum.PUBLISHED);
ElMessage.success('发布成功');
emit('refresh');
@ -77,10 +76,6 @@ async function handlePublish(product: IotProductApi.Product) {
/** 撤销发布 */
async function handleUnpublish(product: IotProductApi.Product) {
await ElMessageBox.confirm(
`确认要撤销发布产品「${product.name}」吗?`,
'确认撤销发布',
);
await updateProductStatus(product.id!, ProductStatusEnum.UNPUBLISHED);
ElMessage.success('撤销发布成功');
emit('refresh');
@ -88,10 +83,6 @@ async function handleUnpublish(product: IotProductApi.Product) {
/** 同步物模型超级表结构 */
async function handleSyncPropertyTable(product: IotProductApi.Product) {
await ElMessageBox.confirm(
`确认要同步产品「${product.name}」的物模型超级表结构吗?`,
'确认同步',
);
await syncProductPropertyTable(product.id!);
ElMessage.success('同步成功');
}
@ -113,32 +104,39 @@ async function handleSyncPropertyTable(product: IotProductApi.Product) {
>
编辑
</ElButton>
<ElButton
<ElPopconfirm
v-if="
product.status === ProductStatusEnum.UNPUBLISHED &&
hasAccessByCodes(['iot:product:update'])
"
type="primary"
@click="handlePublish(product)"
:title="`确认要发布产品「${product.name}」吗?`"
@confirm="handlePublish(product)"
>
发布
</ElButton>
<ElButton
<template #reference>
<ElButton type="primary">发布</ElButton>
</template>
</ElPopconfirm>
<ElPopconfirm
v-if="
product.status === ProductStatusEnum.PUBLISHED &&
hasAccessByCodes(['iot:product:update'])
"
type="danger"
@click="handleUnpublish(product)"
:title="`确认要撤销发布产品「${product.name}」吗?`"
@confirm="handleUnpublish(product)"
>
撤销发布
</ElButton>
<ElButton
<template #reference>
<ElButton type="danger">撤销发布</ElButton>
</template>
</ElPopconfirm>
<ElPopconfirm
v-if="hasAccessByCodes(['iot:product:update'])"
@click="handleSyncPropertyTable(product)"
:title="`确认要同步产品「${product.name}」的物模型超级表结构吗?`"
@confirm="handleSyncPropertyTable(product)"
>
同步物模型表结构
</ElButton>
<template #reference>
<ElButton>同步物模型表结构</ElButton>
</template>
</ElPopconfirm>
</div>
</div>

View File

@ -15,7 +15,15 @@ import {
import { IconifyIcon } from '@vben/icons';
import { CronUtils, formatDateTime } from '@vben/utils';
import { ElCard, ElCol, ElLoading, ElMessage, ElRow, ElTag, ElTooltip } from 'element-plus';
import {
ElCard,
ElCol,
ElLoading,
ElMessage,
ElRow,
ElTag,
ElTooltip,
} from 'element-plus';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import {
@ -368,7 +376,10 @@ const [Grid, gridApi] = useVbenVxeGrid({
row.status === CommonStatusEnum.ENABLE
? 'ant-design:stop-outlined'
: 'ant-design:check-circle-outlined',
onClick: handleToggleStatus.bind(null, row),
popConfirm: {
title: `确认${row.status === CommonStatusEnum.ENABLE ? '停用' : '启用'}场景规则「${row.name}」吗?`,
confirm: handleToggleStatus.bind(null, row),
},
},
{
label: $t('common.edit'),