391 lines
11 KiB
Vue
391 lines
11 KiB
Vue
<script setup lang="ts">
|
|
import { nextTick, ref } from 'vue';
|
|
|
|
import { useVbenModal, z } from '@vben/common-ui';
|
|
|
|
import { message as Message } from 'ant-design-vue';
|
|
|
|
import { useVbenForm } from '#/adapter/form';
|
|
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
|
import {
|
|
postDeviceThingModelManagementCommandCreateAsync,
|
|
postDeviceThingModelManagementCommandDeleteAsync,
|
|
postDeviceThingModelManagementCommandFindByIdAsync,
|
|
postDeviceThingModelManagementCommandPageAsync,
|
|
postDeviceThingModelManagementCommandUpdateAsync,
|
|
postDeviceThingModelManagementPropertyPageAsync,
|
|
} from '#/api-client';
|
|
import { TableAction } from '#/components/table-action';
|
|
import { $t } from '#/locales';
|
|
|
|
defineOptions({
|
|
name: 'DeviceThingModelCommandModal',
|
|
});
|
|
|
|
const deviceThingModelId = ref<string>('');
|
|
const deviceModelName = ref<string>('');
|
|
|
|
const editRow: Record<string, any> = ref({});
|
|
const propertyOptions = ref<Array<{ label: string; value: string }>>([]);
|
|
|
|
// 指令列表
|
|
const [Grid, gridApi] = useVbenVxeGrid({
|
|
formOptions: {
|
|
schema: [],
|
|
showDefaultActions: false,
|
|
},
|
|
gridOptions: {
|
|
columns: [
|
|
{
|
|
field: 'commandName',
|
|
title: '指令名称',
|
|
minWidth: 160,
|
|
showOverflow: 'tooltip',
|
|
},
|
|
{
|
|
field: 'issueCommand',
|
|
title: '下发指令',
|
|
minWidth: 200,
|
|
showOverflow: 'tooltip',
|
|
},
|
|
{
|
|
field: 'propertyArray',
|
|
title: '属性标识符集合',
|
|
minWidth: 200,
|
|
showOverflow: 'tooltip',
|
|
formatter: ({ cellValue }: { cellValue: any }) => {
|
|
if (Array.isArray(cellValue)) {
|
|
return cellValue.join(', ');
|
|
}
|
|
if (typeof cellValue === 'string') {
|
|
try {
|
|
const parsed = JSON.parse(cellValue);
|
|
if (Array.isArray(parsed)) {
|
|
return parsed.join(', ');
|
|
}
|
|
} catch {
|
|
return cellValue;
|
|
}
|
|
}
|
|
return cellValue || '-';
|
|
},
|
|
},
|
|
{
|
|
field: 'action',
|
|
title: $t('common.action'),
|
|
width: 200,
|
|
fixed: 'right',
|
|
slots: { default: 'action' },
|
|
},
|
|
],
|
|
height: 400,
|
|
pagerConfig: {},
|
|
toolbarConfig: {
|
|
custom: true,
|
|
},
|
|
proxyConfig: {
|
|
ajax: {
|
|
query: async ({ page }) => {
|
|
if (!deviceThingModelId.value) {
|
|
return { items: [], totalCount: 0 };
|
|
}
|
|
const { data } = await postDeviceThingModelManagementCommandPageAsync({
|
|
body: {
|
|
pageIndex: page.currentPage,
|
|
pageSize: page.pageSize,
|
|
deviceThingModelId: deviceThingModelId.value,
|
|
},
|
|
});
|
|
return data || { items: [], totalCount: 0 };
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
// 指令新增/编辑弹窗
|
|
const [CommandFormModal, commandFormModalApi] = useVbenModal({
|
|
draggable: true,
|
|
footer: true,
|
|
showCancelButton: true,
|
|
showConfirmButton: true,
|
|
onConfirm: submitCommand,
|
|
onBeforeClose: () => {
|
|
return true;
|
|
},
|
|
onOpenChange: async (isOpen: boolean) => {
|
|
if (isOpen) {
|
|
// 加载当前设备端物模型的属性列表,用于选择属性标识符
|
|
await loadPropertyOptions();
|
|
if (editRow.value.id) {
|
|
// 编辑模式下,加载指令详情
|
|
nextTick(async () => {
|
|
try {
|
|
const { data } = await postDeviceThingModelManagementCommandFindByIdAsync({
|
|
body: { id: editRow.value.id },
|
|
});
|
|
if (data) {
|
|
const values: any = { ...data };
|
|
// 处理 propertyArray 字段
|
|
if (values.propertyArray) {
|
|
if (typeof values.propertyArray === 'string') {
|
|
try {
|
|
values.propertyArray = JSON.parse(values.propertyArray);
|
|
} catch {
|
|
values.propertyArray = [values.propertyArray];
|
|
}
|
|
}
|
|
if (!Array.isArray(values.propertyArray)) {
|
|
values.propertyArray = [];
|
|
}
|
|
} else {
|
|
values.propertyArray = [];
|
|
}
|
|
commandFormApi.setValues(values);
|
|
}
|
|
} catch (error) {
|
|
console.error('加载指令详情失败:', error);
|
|
}
|
|
});
|
|
} else {
|
|
// 新增模式下,清空表单
|
|
commandFormApi.resetForm();
|
|
}
|
|
}
|
|
},
|
|
onCancel: () => {
|
|
commandFormModalApi.close();
|
|
},
|
|
});
|
|
|
|
// 加载属性选项(用于指令的属性标识符选择)
|
|
async function loadPropertyOptions() {
|
|
if (!deviceThingModelId.value) {
|
|
return;
|
|
}
|
|
try {
|
|
const { data } = await postDeviceThingModelManagementPropertyPageAsync({
|
|
body: {
|
|
pageIndex: 1,
|
|
pageSize: 1000,
|
|
deviceThingModelId: deviceThingModelId.value,
|
|
isPage:false
|
|
},
|
|
});
|
|
const items = data?.items || [];
|
|
propertyOptions.value = items.map((item: any) => ({
|
|
label: `${item.standardFieldDisplayName || item.standardFieldName} (${item.standardFieldName})`,
|
|
value: item.ioTPlatformRawFieldName
|
|
}));
|
|
} catch (error) {
|
|
console.error('加载属性列表失败:', error);
|
|
}
|
|
}
|
|
|
|
// 指令表单
|
|
const [CommandForm, commandFormApi] = useVbenForm({
|
|
collapsed: false,
|
|
commonConfig: {
|
|
labelWidth: 140,
|
|
componentProps: {
|
|
class: 'w-4/5',
|
|
},
|
|
},
|
|
layout: 'horizontal',
|
|
schema: [
|
|
{
|
|
component: 'Input',
|
|
fieldName: 'commandName',
|
|
label: '指令名称',
|
|
rules: z
|
|
.preprocess((v) => (v == null ? '' : v), z.string().min(1, $t('common.required'))),
|
|
componentProps: {
|
|
placeholder: $t('common.pleaseInput') + '指令名称',
|
|
},
|
|
},
|
|
{
|
|
component: 'Textarea',
|
|
fieldName: 'issueCommand',
|
|
label: '下发指令',
|
|
rules: z
|
|
.preprocess((v) => (v == null ? '' : v), z.string().min(1, $t('common.required'))),
|
|
componentProps: {
|
|
rows: 4,
|
|
placeholder: $t('common.pleaseInput') + '下发指令(完整的单个下发指令)',
|
|
},
|
|
},
|
|
{
|
|
component: 'Select',
|
|
fieldName: 'propertyArray',
|
|
label: '属性标识符集合',
|
|
rules: z
|
|
.preprocess((v) => (v == null ? [] : v), z.array(z.string()).min(1, '请至少选择一个属性标识符')),
|
|
// 使用函数形式,保证 options 能随着 propertyOptions 的变化而更新
|
|
componentProps: () => ({
|
|
mode: 'multiple',
|
|
placeholder: '请选择属性标识符',
|
|
options: propertyOptions.value,
|
|
showSearch: true,
|
|
filterOption: (input: string, option: any) => {
|
|
return String(option.label)
|
|
.toLowerCase()
|
|
.includes(input.toLowerCase());
|
|
},
|
|
}),
|
|
},
|
|
],
|
|
showCollapseButton: false,
|
|
showDefaultActions: false,
|
|
wrapperClass: 'grid-cols-1',
|
|
});
|
|
|
|
// 打开新增指令弹窗
|
|
function openAddCommandModal() {
|
|
editRow.value = {};
|
|
commandFormModalApi.open();
|
|
}
|
|
|
|
// 打开编辑指令弹窗
|
|
function openEditCommandModal(record: any) {
|
|
editRow.value = record;
|
|
commandFormModalApi.open();
|
|
}
|
|
|
|
// 提交指令(新增/编辑)
|
|
async function submitCommand() {
|
|
const isEdit = !!editRow.value.id;
|
|
const { valid } = await commandFormApi.validate();
|
|
if (!valid) return;
|
|
|
|
const formValues = await commandFormApi.getValues();
|
|
const fetchParams: any = {
|
|
...formValues,
|
|
deviceThingModelId: deviceThingModelId.value,
|
|
// 确保 propertyArray 是数组格式
|
|
propertyArray: Array.isArray(formValues.propertyArray)
|
|
? formValues.propertyArray
|
|
: formValues.propertyArray
|
|
? [formValues.propertyArray]
|
|
: [],
|
|
...(isEdit && { id: editRow.value.id }),
|
|
};
|
|
|
|
try {
|
|
const api = isEdit
|
|
? postDeviceThingModelManagementCommandUpdateAsync
|
|
: postDeviceThingModelManagementCommandCreateAsync;
|
|
const resp = await api({ body: fetchParams });
|
|
if (resp.data) {
|
|
Message.success(
|
|
isEdit ? $t('common.editSuccess') : $t('common.addSuccess'),
|
|
);
|
|
commandFormModalApi.close();
|
|
editRow.value = {};
|
|
await nextTick();
|
|
if (gridApi && gridApi.reload) {
|
|
await gridApi.reload();
|
|
}
|
|
} else {
|
|
Message.error(
|
|
isEdit ? $t('common.editFail') : $t('common.addFail'),
|
|
);
|
|
}
|
|
} catch (error) {
|
|
console.error('提交指令失败:', error);
|
|
Message.error(
|
|
isEdit ? $t('common.editFail') : $t('common.addFail'),
|
|
);
|
|
}
|
|
}
|
|
|
|
// 删除指令
|
|
async function onDeleteCommand(record: any) {
|
|
try {
|
|
const resp = await postDeviceThingModelManagementCommandDeleteAsync({
|
|
body: { id: record.id },
|
|
});
|
|
if (resp.data) {
|
|
Message.success($t('common.deleteSuccess'));
|
|
await nextTick();
|
|
if (gridApi && gridApi.reload) {
|
|
await gridApi.reload();
|
|
}
|
|
} else {
|
|
Message.error($t('common.deleteFail'));
|
|
}
|
|
} catch (error) {
|
|
console.error('删除指令失败:', error);
|
|
Message.error($t('common.deleteFail'));
|
|
}
|
|
}
|
|
|
|
const [Modal, modalApi] = useVbenModal({
|
|
onOpenChange(isOpen: boolean) {
|
|
if (isOpen) {
|
|
const data = modalApi.getData<Record<string, any>>();
|
|
deviceThingModelId.value = data?.deviceThingModelId || '';
|
|
deviceModelName.value = data?.deviceModelName || '';
|
|
// 使用 nextTick 确保 Grid 组件已完全初始化
|
|
nextTick(() => {
|
|
if (gridApi && gridApi.reload) {
|
|
gridApi.reload();
|
|
}
|
|
});
|
|
}
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<Modal :title="`指令管理 - ${deviceModelName || ''}`" class="w-[900px]">
|
|
<Grid>
|
|
<template #toolbar-actions>
|
|
<TableAction
|
|
:actions="[
|
|
{
|
|
label: $t('common.add'),
|
|
type: 'primary',
|
|
icon: 'ant-design:plus-outlined',
|
|
onClick: openAddCommandModal,
|
|
auth: ['AbpIdentity.Users.Create'],
|
|
},
|
|
]"
|
|
/>
|
|
</template>
|
|
|
|
<template #action="{ row }">
|
|
<TableAction
|
|
:actions="[
|
|
{
|
|
label: $t('common.edit'),
|
|
type: 'link',
|
|
size: 'small',
|
|
auth: ['AbpIdentity.Users.Update'],
|
|
onClick: openEditCommandModal.bind(null, row),
|
|
},
|
|
{
|
|
label: $t('common.delete'),
|
|
icon: 'ant-design:delete-outlined',
|
|
type: 'link',
|
|
size: 'small',
|
|
auth: ['AbpIdentity.Users.Delete'],
|
|
popConfirm: {
|
|
title: $t('common.askConfirmDelete'),
|
|
confirm: onDeleteCommand.bind(null, row),
|
|
},
|
|
},
|
|
]"
|
|
/>
|
|
</template>
|
|
</Grid>
|
|
|
|
<!-- 指令新增/编辑弹窗 -->
|
|
<CommandFormModal
|
|
:title="editRow.id ? $t('common.edit') : $t('common.add')"
|
|
class="w-[800px]"
|
|
>
|
|
<CommandForm />
|
|
</CommandFormModal>
|
|
</Modal>
|
|
</template>
|