2025-12-24 11:51:37 +08:00

782 lines
23 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import type { VbenFormProps } from '#/adapter/form';
import type { VxeGridProps } from '#/adapter/vxe-table';
import { h, nextTick, onMounted, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui';
import { message as Message, Tag } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import {
postIoTplatformThingModelInfoCopyAnotherThingModelAsync,
postIoTplatformThingModelInfoCopyStandardThingModel,
postIoTplatformThingModelInfoCreateAsync,
postIoTplatformThingModelInfoDeleteAsync,
postIoTplatformThingModelInfoPageAsync,
postIoTplatformThingModelInfoUpdateAsync,
} from '#/api-client';
import { TableAction } from '#/components/table-action';
import { $t } from '#/locales';
import {
copyStandardThingModelFormSchema,
copyThingModelFormSchema,
getAddThingModelFormSchema,
getEditThingModelFormSchema,
querySchema,
tableSchema,
} from './schema';
defineOptions({
name: 'IoTPlatformThingModelInfo',
});
const route = useRoute();
// 从路由参数获取产品信息
const productId = ref<string>((route.query.productId as string) || '');
const productName = ref<string>((route.query.productName as string) || '');
const ioTPlatform = ref<string>((route.query.ioTPlatform as string) || '2');
const formOptions: VbenFormProps = {
schema: querySchema.value,
initialValues: {
ioTPlatform: route.query.ioTPlatform
? String(route.query.ioTPlatform)
: undefined,
ioTPlatformProductId: route.query.productId
? String(route.query.productId)
: undefined,
},
submitOnChange: false,
handleValuesChange: async (values, changedFields) => {
// 当平台类型变化时清空产品ID
if (changedFields.includes('ioTPlatform') && values.ioTPlatform) {
ioTPlatform.value = String(values.ioTPlatform);
// 清空产品ID因为平台变化了
if (gridApi?.formApi) {
await gridApi.formApi.setValues({
ioTPlatformProductId: undefined,
});
}
productId.value = '';
productName.value = '';
}
// 当产品ID变化时更新响应式变量并重新加载数据
if (changedFields.includes('ioTPlatformProductId')) {
if (values.ioTPlatformProductId) {
productId.value = String(values.ioTPlatformProductId);
// 产品名称可以从 ApiSelect 的选项中获取,不需要额外请求
// 如果需要产品名称,可以通过表单字段的选项来获取
} else {
productId.value = '';
productName.value = '';
}
// 延迟重新加载数据,确保表单值已更新
await nextTick();
setTimeout(async () => {
if (gridApi && gridApi.reload) {
try {
// 确保使用最新的表单值进行查询
await gridApi.reload();
} catch (error) {
console.error('重新加载数据时出错:', error);
}
}
}, 100);
}
},
};
const gridOptions: VxeGridProps<any> = {
checkboxConfig: {
highlight: true,
labelField: 'thingModelName',
},
columns: tableSchema.value,
height: 'auto',
keepSource: true,
pagerConfig: {},
toolbarConfig: {
custom: true,
},
customConfig: {
storage: true,
},
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
// 总是从表单API获取最新的表单值确保参数完整分页、刷新时formValues可能不完整
const currentFormValues = gridApi?.formApi
? await gridApi.formApi.getValues()
: formValues || {};
// 优先使用从表单API获取的值最新的如果没有则使用传入的formValues
const finalFormValues = { ...formValues, ...currentFormValues };
const currentPlatform = finalFormValues?.ioTPlatform;
const currentProductId = finalFormValues?.ioTPlatformProductId;
// 即使没有产品ID或平台也触发查询让后端处理参数验证
try {
// 构建查询参数
const queryParams: any = {
pageIndex: page.currentPage,
pageSize: page.pageSize,
};
// 添加搜索关键词
if (finalFormValues?.SearchKeyWords) {
queryParams.searchKeyWords = finalFormValues.SearchKeyWords;
}
// 添加平台参数(必须)
if (currentPlatform) {
queryParams.ioTPlatform = Number.parseInt(
String(currentPlatform),
) as 1 | 2;
}
// 添加产品ID参数必须
if (currentProductId) {
queryParams.ioTPlatformProductId = String(currentProductId);
}
const { data } = await postIoTplatformThingModelInfoPageAsync({
body: queryParams,
});
// 更新数据状态,检查是否有数据
hasData.value = data?.items && data.items.length > 0;
return data || { items: [], totalCount: 0 };
} catch (error) {
console.error('查询物模型信息失败:', error);
hasData.value = false;
return {
items: [],
totalCount: 0,
};
}
},
},
},
};
const [Grid, gridApi] = useVbenVxeGrid({ formOptions, gridOptions });
const editRow: Record<string, any> = ref({});
// 跟踪数据状态,用于控制按钮显示
const hasData = ref(true);
const [ThingModelModal, thingModelModalApi] = useVbenModal({
draggable: true,
footer: true,
showCancelButton: true,
showConfirmButton: true,
onConfirm: submit,
onBeforeClose: () => {
return true;
},
onOpenChange: async (isOpen: boolean) => {
if (isOpen) {
// 打开弹窗时设置平台和产品ID到表单中用于下拉框依赖
await nextTick();
const formApi = editRow.value.id ? editFormApi : addFormApi;
const isEdit = !!editRow.value.id;
// 编辑时从选中对象获取,新增时从搜索表单获取
let platformValue: 1 | 2;
let productIdValue: string;
if (isEdit) {
// 编辑时从 editRow.value 获取
platformValue = editRow.value.ioTPlatform
? ((typeof editRow.value.ioTPlatform === 'string'
? Number.parseInt(editRow.value.ioTPlatform)
: editRow.value.ioTPlatform) as 1 | 2)
: (Number.parseInt(ioTPlatform.value) as 1 | 2);
productIdValue = editRow.value.ioTPlatformProductId || productId.value;
} else {
// 新增时从搜索表单获取最新的值
const formValues = gridApi?.formApi
? await gridApi.formApi.getValues()
: {};
platformValue = formValues.ioTPlatform
? ((typeof formValues.ioTPlatform === 'string'
? Number.parseInt(formValues.ioTPlatform)
: formValues.ioTPlatform) as 1 | 2)
: (Number.parseInt(ioTPlatform.value) as 1 | 2);
productIdValue = formValues.ioTPlatformProductId || productId.value;
// 同步更新响应式变量
if (formValues.ioTPlatform) {
ioTPlatform.value = String(formValues.ioTPlatform);
}
if (formValues.ioTPlatformProductId) {
productId.value = String(formValues.ioTPlatformProductId);
}
}
console.log('设置表单值:', {
isEdit,
platformValue,
productIdValue,
editRowValue: isEdit ? editRow.value : null,
});
await formApi.setValues({
...(isEdit ? editRow.value : {}),
_ioTPlatform: platformValue,
_ioTPlatformProductId: productIdValue,
});
// 手动触发平台物模型编码字段的重新加载
setTimeout(() => {
const fieldRef = formApi.getFieldComponentRef(
'ioTPlatformRawFieldName',
);
if (fieldRef && typeof fieldRef.updateParam === 'function') {
fieldRef.updateParam({
body: {
ioTPlatformType: platformValue,
ioTPlatformProductId: productIdValue,
},
});
}
}, 100);
}
},
onCancel: () => {
thingModelModalApi.close();
},
});
const [CopyModal, copyModalApi] = useVbenModal({
draggable: true,
footer: true,
showCancelButton: true,
showConfirmButton: true,
onConfirm: submitCopy,
onBeforeClose: () => {
return true;
},
onCancel: () => {
copyModalApi.close();
},
});
// 复制标准模型弹窗
const [CopyStandardModal, copyStandardModalApi] = useVbenModal({
draggable: true,
footer: true,
showCancelButton: true,
showConfirmButton: true,
onConfirm: submitCopyStandard,
onBeforeClose: () => {
return true;
},
onCancel: () => {
copyStandardModalApi.close();
},
});
// 创建新增表单 schema传入获取平台和产品ID的函数作为后备方案
// 注意:实际使用时,值会从表单的 _ioTPlatform 和 _ioTPlatformProductId 字段获取
const addThingModelFormSchema = getAddThingModelFormSchema(
() => {
// 作为后备方案,返回响应式变量的值
return ioTPlatform.value
? (Number.parseInt(ioTPlatform.value) as 1 | 2)
: undefined;
},
() => {
// 作为后备方案,返回响应式变量的值
return productId.value || undefined;
},
);
const [AddForm, addFormApi] = useVbenForm({
collapsed: false,
commonConfig: {
labelWidth: 150,
labelClass: 'whitespace-nowrap',
componentProps: {
class: 'w-4/5',
},
},
layout: 'horizontal',
schema: addThingModelFormSchema.value,
showCollapseButton: false,
showDefaultActions: false,
wrapperClass: 'grid-cols-2',
});
// 创建编辑表单 schema传入获取平台和产品ID的函数编辑时从 editRow 获取)
const editThingModelFormSchema = getEditThingModelFormSchema(
() => {
// 编辑时优先从 editRow 获取
if (editRow.value?.ioTPlatform) {
return typeof editRow.value.ioTPlatform === 'string'
? Number.parseInt(editRow.value.ioTPlatform)
: editRow.value.ioTPlatform;
}
// 如果没有,使用响应式变量
return ioTPlatform.value
? (Number.parseInt(ioTPlatform.value) as 1 | 2)
: undefined;
},
() => {
// 编辑时优先从 editRow 获取
return editRow.value?.ioTPlatformProductId || productId.value || undefined;
},
);
const [EditForm, editFormApi] = useVbenForm({
collapsed: false,
commonConfig: {
labelWidth: 150,
labelClass: 'whitespace-nowrap',
componentProps: {
class: 'w-4/5',
},
},
layout: 'horizontal',
schema: editThingModelFormSchema.value,
showCollapseButton: false,
showDefaultActions: false,
wrapperClass: 'grid-cols-2',
});
const [CopyForm, copyFormApi] = useVbenForm({
collapsed: false,
commonConfig: {
labelWidth: 110,
componentProps: {
class: 'w-4/5',
},
},
layout: 'horizontal',
schema: copyThingModelFormSchema.value,
showCollapseButton: false,
showDefaultActions: false,
wrapperClass: 'grid-cols-2',
});
// 复制标准模型表单(多选物模型类型)
const [CopyStandardForm, copyStandardFormApi] = useVbenForm({
collapsed: false,
commonConfig: {
labelWidth: 160,
componentProps: {
class: 'w-4/5',
},
},
layout: 'horizontal',
schema: copyStandardThingModelFormSchema.value,
showCollapseButton: false,
showDefaultActions: false,
wrapperClass: 'grid-cols-1',
});
// 监听路由参数变化,自动加载数据
watch(
() => [route.query.productId, route.query.ioTPlatform],
async ([newProductId, newIoTPlatform]) => {
if (newProductId) {
productId.value = newProductId as string;
}
if (newIoTPlatform) {
ioTPlatform.value = newIoTPlatform as string;
}
if (route.query.productName) {
productName.value = route.query.productName as string;
}
// 延迟执行,确保组件完全初始化
if (gridApi) {
setTimeout(async () => {
try {
await gridApi.reload();
} catch (error) {
console.error('加载数据时出错:', error);
}
}, 100);
}
},
{ immediate: false },
);
// 页面初始化时加载数据
onMounted(async () => {
// 从路由参数初始化
if (route.query.productId) {
productId.value = route.query.productId as string;
}
if (route.query.productName) {
productName.value = route.query.productName as string;
}
if (route.query.ioTPlatform) {
ioTPlatform.value = route.query.ioTPlatform as string;
}
// 延迟加载数据,确保表格已初始化
// 即使没有 productId也要触发一次查询让表格显示空白状态
await nextTick();
setTimeout(async () => {
if (gridApi && gridApi.reload) {
try {
// 设置表单值(如果有路由参数)
const formValues = await gridApi.formApi.getValues();
if (route.query.ioTPlatform && !formValues.ioTPlatform) {
await gridApi.formApi.setValues({
ioTPlatform: route.query.ioTPlatform,
});
}
if (route.query.productId && !formValues.ioTPlatformProductId) {
await gridApi.formApi.setValues({
ioTPlatformProductId: route.query.productId,
});
}
await nextTick();
// 无论是否有参数,都触发查询
await gridApi.reload();
} catch (error) {
console.error('初始化加载数据时出错:', error);
}
}
}, 300);
});
// 新增和编辑提交的逻辑
async function submit() {
// 检查是否有产品ID
if (!productId.value) {
Message.error('产品ID不存在无法保存物模型信息');
return;
}
const isEdit = !!editRow.value.id;
const formApi = isEdit ? editFormApi : addFormApi;
const api = isEdit
? postIoTplatformThingModelInfoUpdateAsync
: postIoTplatformThingModelInfoCreateAsync;
const { valid } = await formApi.validate();
if (!valid) return;
const formValues = await formApi.getValues();
const fetchParams: any = {
...formValues,
// 自动添加平台和产品信息
ioTPlatform: Number.parseInt(ioTPlatform.value) as 1 | 2,
ioTPlatformProductId: productId.value,
// 编辑时需要添加ID
...(isEdit && { id: editRow.value.id }),
};
try {
const resp = await api({ body: fetchParams });
if (resp.data) {
Message.success(
editRow.value.id ? $t('common.editSuccess') : $t('common.addSuccess'),
);
thingModelModalApi.close();
editRow.value = {};
gridApi.reload();
} else {
Message.error(
editRow.value.id ? $t('common.editFail') : $t('common.addFail'),
);
}
} catch (error) {
console.error('提交失败:', error);
}
}
async function onEdit(record: any) {
editRow.value = record;
// 编辑时从选中对象获取平台和产品ID
const platformValue = record.ioTPlatform
? ((typeof record.ioTPlatform === 'string'
? Number.parseInt(record.ioTPlatform)
: record.ioTPlatform) as 1 | 2)
: (Number.parseInt(ioTPlatform.value) as 1 | 2);
const productIdValue = record.ioTPlatformProductId || productId.value;
thingModelModalApi.open();
await nextTick();
setTimeout(async () => {
await editFormApi.setValues({
...record,
_ioTPlatform: platformValue,
_ioTPlatformProductId: productIdValue,
});
// 手动触发平台物模型编码字段的重新加载
const fieldRef = editFormApi.getFieldComponentRef(
'ioTPlatformRawFieldName',
);
if (fieldRef && typeof fieldRef.updateParam === 'function') {
fieldRef.updateParam({
body: {
ioTPlatformType: platformValue,
ioTPlatformProductId: productIdValue,
},
});
}
}, 100);
}
const openAddModal = async () => {
editRow.value = {};
// 打开新增弹窗时从搜索表单中获取平台和产品ID确保是最新的值
const formValues = gridApi?.formApi ? await gridApi.formApi.getValues() : {};
const platformValue = formValues.ioTPlatform
? ((typeof formValues.ioTPlatform === 'string'
? Number.parseInt(formValues.ioTPlatform)
: formValues.ioTPlatform) as 1 | 2)
: (Number.parseInt(ioTPlatform.value) as 1 | 2);
const productIdValue = formValues.ioTPlatformProductId || productId.value;
// 更新响应式变量(保持同步)
if (formValues.ioTPlatform) {
ioTPlatform.value = String(formValues.ioTPlatform);
}
if (formValues.ioTPlatformProductId) {
productId.value = String(formValues.ioTPlatformProductId);
}
thingModelModalApi.open();
// 确保值已设置
await nextTick();
setTimeout(async () => {
await addFormApi.setValues({
_ioTPlatform: platformValue,
_ioTPlatformProductId: productIdValue,
});
// 手动触发平台物模型编码字段的重新加载
const fieldRef = addFormApi.getFieldComponentRef('ioTPlatformRawFieldName');
if (fieldRef && typeof fieldRef.updateParam === 'function') {
fieldRef.updateParam({
body: {
ioTPlatformType: platformValue,
ioTPlatformProductId: productIdValue,
},
});
}
}, 100);
};
// 打开复制已有模型模态框
const openCopyAnotherThingModelModal = async () => {
console.log('打开复制模态框,当前参数:', {
productId: productId.value,
productName: productName.value,
ioTPlatform: ioTPlatform.value,
});
copyModalApi.open();
};
// 复制提交逻辑
async function submitCopy() {
// 检查是否有产品ID
if (!productId.value) {
Message.error('产品ID不存在无法复制物模型信息');
return;
}
const { valid } = await copyFormApi.validate();
if (!valid) return;
const formValues = await copyFormApi.getValues();
console.log('复制提交参数:', {
formValues,
params: {
productId: productId.value,
productName: productName.value,
ioTPlatform: ioTPlatform.value,
},
});
try {
const resp = await postIoTplatformThingModelInfoCopyAnotherThingModelAsync({
body: {
ioTPlatform: Number.parseInt(ioTPlatform.value) as 1 | 2,
ioTPlatformProductId: productId.value,
sourceProductId: formValues.ioTPlatformProductId,
},
});
if (resp.data) {
Message.success('复制模型成功');
copyModalApi.close();
gridApi.reload();
} else {
Message.error('复制模型失败');
}
} catch (error) {
console.error('复制模型失败:', error);
}
}
// 打开复制标准模型模态框(逻辑与“复制已有模型”保持一致)
const openCopyStandardThingModelModal = () => {
console.log('打开复制标准模型模态框,当前参数:', {
productId: productId.value,
productName: productName.value,
ioTPlatform: ioTPlatform.value,
});
copyStandardModalApi.open();
};
// 复制标准模型提交逻辑(带物模型类型多选)
async function submitCopyStandard() {
// 检查是否有产品ID
if (!productId.value) {
Message.error('产品ID不存在无法复制标准模型');
return;
}
const { valid } = await copyStandardFormApi.validate();
if (!valid) return;
const formValues = await copyStandardFormApi.getValues();
console.log('复制标准模型提交参数:', {
formValues,
params: {
productId: productId.value,
productName: productName.value,
ioTPlatform: ioTPlatform.value,
},
});
try {
const resp = await postIoTplatformThingModelInfoCopyStandardThingModel({
body: {
ioTPlatform: Number.parseInt(ioTPlatform.value) as 1 | 2,
ioTPlatformProductId: productId.value,
// 按物模型类型多选复制(使用字段 filedTypes值为字典 key 列表)
filedTypes: formValues.filedTypes,
},
});
if (resp.data) {
Message.success('复制标准模型成功');
copyStandardModalApi.close();
gridApi.reload();
} else {
Message.error('复制标准模型失败');
}
} catch (error) {
console.error('复制标准模型失败:', error);
}
}
// 删除函数
async function onDel(record: any) {
try {
const resp = await postIoTplatformThingModelInfoDeleteAsync({
body: { id: record.id },
});
if (resp.data) {
Message.success($t('common.deleteSuccess'));
gridApi.reload();
} else {
Message.error($t('common.deleteFail'));
}
} catch (error) {
console.error('删除失败:', error);
}
}
// 旧的“复制标准模型”直调接口函数已不再使用,保留逻辑由新的弹窗 + submitCopyStandard 代替
</script>
<template>
<Page auto-content-height>
<Grid>
<template #toolbar-actions>
<TableAction :actions="[
{
label: $t('common.add'),
type: 'primary',
icon: 'ant-design:plus-outlined',
onClick: openAddModal.bind(null),
auth: ['AbpIdentity.Users.Create'],
disabled: !productId,
},
{
label: $t('abp.thingModelInfos.copyStandardThingModel'),
type: 'default',
icon: 'ant-design:copy-outlined',
onClick: openCopyStandardThingModelModal,
auth: ['AbpIdentity.Users.Create'],
disabled: !productId,
},
{
label: $t('abp.thingModelInfos.copyAnotherThingModelModal'),
type: 'default',
icon: 'ant-design:copy-outlined',
onClick: openCopyAnotherThingModelModal,
auth: ['AbpIdentity.Users.Create'],
ifShow: !hasData,
disabled: !productId,
},
]" />
</template>
<template #isValueNeedConvert="{ row }">
<component :is="h(
Tag,
{ color: row.isValueNeedConvert ? 'blue' : 'default' },
() => (row.isValueNeedConvert ? '是' : '否'),
)
" />
</template>
<template #action="{ row }">
<TableAction :actions="[
{
label: $t('common.edit'),
type: 'link',
size: 'small',
auth: ['AbpIdentity.Users.Update'],
onClick: onEdit.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: onDel.bind(null, row),
},
},
]" />
</template>
</Grid>
<ThingModelModal :title="editRow.id ? $t('common.edit') : $t('common.add')" class="w-[800px]">
<component :is="editRow.id ? EditForm : AddForm" />
</ThingModelModal>
<!-- 复制已有模型模态框 -->
<CopyModal title="复制已有模型" class="w-[600px]">
<CopyForm />
</CopyModal>
<!-- 复制标准模型按物模型类型多选模态框 -->
<CopyStandardModal title="复制标准模型" class="w-[600px]">
<CopyStandardForm />
</CopyStandardModal>
</Page>
</template>