Compare commits

...

2 Commits

Author SHA1 Message Date
ChenYi
288b153e43 平台产品聚合服务 2025-12-17 15:51:26 +08:00
ChenYi
fdc07134a8 修改产品物模型管理按钮,更新nswag接口信息 2025-12-17 11:19:31 +08:00
7 changed files with 2543 additions and 214 deletions

12
.vscode/settings.json vendored
View File

@ -237,5 +237,15 @@
"nolebase",
"rollup",
"vitest"
]
],
"editor.gotoLocation.alternativeDeclarationCommand": "editor.action.revealDefinition",
"editor.gotoLocation.alternativeDefinitionCommand": "editor.action.revealDefinition",
"editor.gotoLocation.alternativeTypeDefinitionCommand": "editor.action.revealDefinition",
"editor.selectionHighlight": false,
"files.autoSave": "onFocusChange",
"editor.quickSuggestions": {
"other": "on",
"comments": "off",
"strings": "on"
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -23,8 +23,6 @@ import {
import { TableAction } from '#/components/table-action';
import { $t } from '#/locales';
import ThingModelInfoModal from '#/views/thingmodelinfo/ioTPlatformThingModelInfo/index.vue';
import {
addProductFormSchema,
editProductFormSchemaEdit,
@ -78,10 +76,6 @@ const editRow: Record<string, any> = ref({});
//
let selectedFile: File | null = null;
//
const thingModelModalVisible = ref(false);
const currentProductInfo = ref<any>({});
//
setFileSelectedCallback((file) => {
selectedFile = file;
@ -330,22 +324,15 @@ function onDeviceManagement(record: any) {
//
function onThingModelManagement(record: any) {
console.log('物模型管理按钮被点击', record);
//
currentProductInfo.value = {
productId: record.ioTPlatformProductId,
// ID
router.push({
path: '/thingmodelinfo/ioTPlatformThingModelInfo',
query: {
productId: record.ioTPlatformProductId, // ID
productName: record.productName,
ioTPlatform: '2', // OneNET2
};
console.log('设置产品信息:', currentProductInfo.value);
//
thingModelModalVisible.value = true;
console.log('模态框状态设置为:', thingModelModalVisible.value);
}
//
function closeThingModelModal() {
thingModelModalVisible.value = false;
currentProductInfo.value = {};
},
});
}
</script>
@ -428,14 +415,5 @@ function closeThingModelModal() {
<UserModal :title="editRow.id ? $t('common.edit') : $t('common.add')" class="w-[800px]">
<component :is="editRow.id ? EditForm : AddForm" />
</UserModal>
<!-- 物模型信息模态框 -->
<ThingModelInfoModal
v-model:visible="thingModelModalVisible"
:product-id="currentProductInfo.productId"
:product-name="currentProductInfo.productName"
:io-t-platform="currentProductInfo.ioTPlatform"
@close="closeThingModelModal"
/>
</Page>
</template>

View File

@ -2,21 +2,24 @@
import type { VbenFormProps } from '#/adapter/form';
import type { VxeGridProps } from '#/adapter/vxe-table';
import { h, nextTick, ref, watch } from 'vue';
import { h, nextTick, onMounted, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { useVbenModal } from '@vben/common-ui';
import { Page, useVbenModal } from '@vben/common-ui';
import { message as Message, Modal, Tag } from 'ant-design-vue';
import { message as Message, Tag } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import {
postCtWingProductListAsync,
postIoTplatformThingModelInfoCopyAnotherThingModelAsync,
postIoTplatformThingModelInfoCopyStandardThingModel,
postIoTplatformThingModelInfoCreateAsync,
postIoTplatformThingModelInfoDeleteAsync,
postIoTplatformThingModelInfoPageAsync,
postIoTplatformThingModelInfoUpdateAsync,
postOneNetProductListAsync,
} from '#/api-client';
import { TableAction } from '#/components/table-action';
import { $t } from '#/locales';
@ -30,32 +33,88 @@ import {
} from './schema';
defineOptions({
name: 'ThingModelInfoModal',
name: 'IoTPlatformThingModelInfo',
});
const props = withDefaults(defineProps<Props>(), {
visible: false,
productId: '',
productName: '',
ioTPlatform: '2',
});
const route = useRoute();
// emits
const emit = defineEmits<{
close: [];
'update:visible': [value: boolean];
}>();
// props
interface Props {
visible?: boolean;
productId?: string;
productName?: string;
ioTPlatform?: string;
}
//
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')) {
if (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);
//
const platform = values.ioTPlatform;
if (platform) {
try {
const api = platform === 2 || platform === '2'
? postOneNetProductListAsync
: platform === 1 || platform === '1'
? postCtWingProductListAsync
: null;
if (api) {
const { data } = await api({
body: {
pageIndex: 1,
pageSize: 1000,
},
});
const items = data?.items || [];
const selectedProduct = items.find((item: any) =>
String(item.ioTPlatformProductId) === String(values.ioTPlatformProductId)
);
if (selectedProduct) {
productName.value = selectedProduct.productName || '';
}
}
} catch (error) {
console.error('获取产品名称失败:', error);
}
}
} else {
productId.value = '';
productName.value = '';
}
//
setTimeout(async () => {
if (gridApi && gridApi.reload) {
try {
await gridApi.reload();
} catch (error) {
console.error('重新加载数据时出错:', error);
}
}
}, 100);
}
},
};
const gridOptions: VxeGridProps<any> = {
@ -76,20 +135,40 @@ const gridOptions: VxeGridProps<any> = {
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
// 使使
const currentPlatform = formValues?.ioTPlatform || ioTPlatform.value;
const currentProductId = formValues?.ioTPlatformProductId || productId.value;
// ID
if (!currentProductId || !currentPlatform) {
hasData.value = false;
return {
items: [],
totalCount: 0,
};
}
try {
const { data } = await postIoTplatformThingModelInfoPageAsync({
query: {
input: {
body: {
pageIndex: page.currentPage,
pageSize: page.pageSize,
ioTPlatform: Number.parseInt(props.ioTPlatform) as 1 | 2,
ioTPlatformProductId: props.productId,
ioTPlatform: Number.parseInt(String(currentPlatform)) as 1 | 2,
ioTPlatformProductId: String(currentProductId),
...(formValues?.SearchKeyWords && { searchKeyWords: formValues.SearchKeyWords }),
},
},
});
//
hasData.value = data?.items && data.items.length > 0;
return data;
return data || { items: [], totalCount: 0 };
} catch (error) {
console.error('查询物模型信息失败:', error);
hasData.value = false;
return {
items: [],
totalCount: 0,
};
}
},
},
},
@ -183,41 +262,84 @@ const [CopyForm, copyFormApi] = useVbenForm({
wrapperClass: 'grid-cols-2',
});
// props
//
watch(
() => [props.visible, props.productId, props.ioTPlatform],
async ([visible, productId, ioTPlatform]) => {
console.log('物模型模态框props变化:', { visible, productId, ioTPlatform });
console.log('所有props:', props);
if (visible && productId) {
() => [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 {
//
const filterValues: any = {};
// ioTPlatformProductId API props.productId
// SearchKeyWords
console.log('设置筛选条件:', filterValues);
//
if (Object.keys(filterValues).length > 0) {
await gridApi.formApi.setValues(filterValues);
}
// 使 productId
await gridApi.reload();
} catch (error) {
console.error('设置筛选条件时出错:', error);
console.error('加载数据时出错:', error);
}
}, 100);
}
},
{ immediate: true },
{ 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 {
//
if (route.query.ioTPlatform || route.query.productId) {
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
@ -230,14 +352,14 @@ async function submit() {
const fetchParams: any = {
...formValues,
//
ioTPlatform: Number.parseInt(props.ioTPlatform) as 1 | 2,
ioTPlatformProductId: props.productId,
ioTPlatform: Number.parseInt(ioTPlatform.value) as 1 | 2,
ioTPlatformProductId: productId.value,
// ID
...(isEdit && { id: editRow.value.id }),
};
try {
const resp = await api({ query: { input: fetchParams } });
const resp = await api({ body: fetchParams });
if (resp.data) {
Message.success(
editRow.value.id ? $t('common.editSuccess') : $t('common.addSuccess'),
@ -270,16 +392,22 @@ const openAddModal = async () => {
//
const openCopyAnotherThingModelModal = async () => {
console.log('打开复制模态框,当前props:', {
productId: props.productId,
productName: props.productName,
ioTPlatform: props.ioTPlatform,
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;
@ -287,22 +415,20 @@ async function submitCopy() {
console.log('复制提交参数:', {
formValues,
props: {
productId: props.productId,
productName: props.productName,
ioTPlatform: props.ioTPlatform,
params: {
productId: productId.value,
productName: productName.value,
ioTPlatform: ioTPlatform.value,
},
});
try {
const resp = await postIoTplatformThingModelInfoCopyAnotherThingModelAsync({
query: {
input: {
ioTPlatform: Number.parseInt(props.ioTPlatform) as 1 | 2,
ioTPlatformProductId: props.productId,
body: {
ioTPlatform: Number.parseInt(ioTPlatform.value) as 1 | 2,
ioTPlatformProductId: productId.value,
sourceProductId: formValues.ioTPlatformProductId,
},
},
});
if (resp.data) {
@ -322,9 +448,7 @@ async function submitCopy() {
async function onDel(record: any) {
try {
const resp = await postIoTplatformThingModelInfoDeleteAsync({
query: {
input: { id: record.id },
},
body: { id: record.id },
});
if (resp.data) {
Message.success($t('common.deleteSuccess'));
@ -340,13 +464,17 @@ async function onDel(record: any) {
//
async function copyStandardThingModel() {
// ID
if (!productId.value) {
Message.error('产品ID不存在无法复制标准模型');
return;
}
try {
const resp = await postIoTplatformThingModelInfoCopyStandardThingModel({
query: {
input: {
ioTPlatform: Number.parseInt(props.ioTPlatform) as 1 | 2,
ioTPlatformProductId: props.productId,
},
body: {
ioTPlatform: Number.parseInt(ioTPlatform.value) as 1 | 2,
ioTPlatformProductId: productId.value,
},
});
if (resp.data) {
@ -360,20 +488,11 @@ async function copyStandardThingModel() {
Message.error('复制标准模型失败');
}
}
//
function closeModal() {
emit('update:visible', false);
emit('close');
}
</script>
<template>
<Modal :open="visible" :title="`${props.ioTPlatform === 1 ? 'CTWing' : 'OneNET'}物模型管理 - ${productName || '产品'}`"
width="90%" :footer="null" @cancel="closeModal" @ok="closeModal"
:body-style="{ height: '70vh', overflow: 'hidden' }">
<div style="display: flex; flex-direction: column; height: 100%">
<Grid style="flex: 1; overflow: hidden">
<Page auto-content-height>
<Grid>
<template #toolbar-actions>
<TableAction :actions="[
{
@ -382,6 +501,7 @@ function closeModal() {
icon: 'ant-design:plus-outlined',
onClick: openAddModal.bind(null),
auth: ['AbpIdentity.Users.Create'],
disabled: !productId,
},
{
label: $t('abp.thingModelInfos.copyStandardThingModel'),
@ -389,6 +509,7 @@ function closeModal() {
icon: 'ant-design:copy-outlined',
onClick: copyStandardThingModel,
auth: ['AbpIdentity.Users.Create'],
disabled: !productId,
},
{
label: $t('abp.thingModelInfos.copyAnotherThingModelModal'),
@ -397,6 +518,7 @@ function closeModal() {
onClick: openCopyAnotherThingModelModal,
auth: ['AbpIdentity.Users.Create'],
ifShow: !hasData,
disabled: !productId,
},
]" />
</template>
@ -433,7 +555,6 @@ function closeModal() {
]" />
</template>
</Grid>
</div>
<ThingModelModal :title="editRow.id ? $t('common.edit') : $t('common.add')" class="w-[800px]">
<component :is="editRow.id ? EditForm : AddForm" />
</ThingModelModal>
@ -442,5 +563,5 @@ function closeModal() {
<CopyModal title="复制已有模型" class="w-[600px]">
<CopyForm />
</CopyModal>
</Modal>
</Page>
</template>

View File

@ -6,11 +6,95 @@ import dayjs from 'dayjs';
import {
getCommonGetSelectList,
postAggregationIoTplatformGetIoTplatformProductInfoAsync,
postOneNetProductListAsync,
} from '#/api-client';
import { $t } from '#/locales';
export const querySchema = computed(() => [
{
component: 'ApiSelect',
fieldName: 'ioTPlatform',
label: $t('abp.deviceInfos.ioTPlatform'),
componentProps: {
api: getCommonGetSelectList,
params: {
query: {
typeName: 'IoTPlatformTypeEnum',
},
},
labelField: 'value',
valueField: 'key',
optionsPropName: 'options',
immediate: true,
allowClear: true,
placeholder: `${$t('common.pleaseSelect')}${$t('abp.deviceInfos.ioTPlatform')}`,
afterFetch: (res: any) => {
// 确保返回的是数组格式
if (Array.isArray(res)) {
return res;
}
if (res && Array.isArray(res.items)) {
return res.items;
}
if (res && Array.isArray(res.data)) {
return res.data;
}
return [];
},
},
},
{
component: 'ApiSelect',
fieldName: 'ioTPlatformProductId',
label: $t('common.BelongingProductName'),
dependencies: {
show(values: any) {
return !!values.ioTPlatform;
},
triggerFields: ['ioTPlatform'],
},
componentProps: (formValues: any) => {
const platform = formValues?.ioTPlatform;
return {
api: platform
? postAggregationIoTplatformGetIoTplatformProductInfoAsync
: null,
params: {
body: {
// 聚合服务要求 JSON Body 格式参数
ioTPlatformType:
typeof platform === 'string'
? Number.parseInt(platform)
: platform,
},
},
labelField: 'productName',
valueField: 'ioTPlatformProductId',
optionsPropName: 'options',
immediate: false,
allowClear: true,
placeholder: `${$t('common.pleaseSelect')}${$t('common.BelongingProductName')}`,
afterFetch: (res: any) => {
// 确保返回的是数组格式
if (Array.isArray(res)) {
return res;
}
if (res && Array.isArray(res.items)) {
return res.items;
}
if (res && Array.isArray(res.data)) {
return res.data;
}
if (res && res.data && Array.isArray(res.data.items)) {
return res.data.items;
}
return [];
},
};
},
},
{
component: 'Input',
fieldName: 'SearchKeyWords',