420 lines
11 KiB
Vue
420 lines
11 KiB
Vue
<script setup lang="ts">
|
||
import type { VbenFormProps } from '#/adapter/form';
|
||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||
|
||
import { h, nextTick, ref } from 'vue';
|
||
import { useRouter } 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 {
|
||
postFilesDownload,
|
||
postFilesUpload,
|
||
postOneNetProductDeleteAsync,
|
||
postOneNetProductInsertAsync,
|
||
postOneNetProductListAsync,
|
||
postOneNetProductModifyAsync,
|
||
postOneNetProductProductStatusChangeAsync,
|
||
} from '#/api-client';
|
||
import { TableAction } from '#/components/table-action';
|
||
import { $t } from '#/locales';
|
||
|
||
import {
|
||
addProductFormSchema,
|
||
editProductFormSchemaEdit,
|
||
querySchema,
|
||
setFileSelectedCallback,
|
||
tableSchema,
|
||
} from './schema';
|
||
|
||
defineOptions({
|
||
name: 'OneNETProduct',
|
||
});
|
||
|
||
const router = useRouter();
|
||
const formOptions: VbenFormProps = {
|
||
schema: querySchema.value,
|
||
};
|
||
const gridOptions: VxeGridProps<any> = {
|
||
checkboxConfig: {
|
||
highlight: true,
|
||
labelField: 'name',
|
||
},
|
||
columns: tableSchema.value,
|
||
height: 'auto',
|
||
keepSource: true,
|
||
pagerConfig: {},
|
||
toolbarConfig: {
|
||
custom: true,
|
||
},
|
||
customConfig: {
|
||
storage: true,
|
||
},
|
||
proxyConfig: {
|
||
ajax: {
|
||
query: async ({ page }, formValues) => {
|
||
const { data } = await postOneNetProductListAsync({
|
||
body: {
|
||
pageIndex: page.currentPage,
|
||
pageSize: page.pageSize,
|
||
...formValues,
|
||
},
|
||
});
|
||
return data;
|
||
},
|
||
},
|
||
},
|
||
};
|
||
|
||
const [Grid, gridApi] = useVbenVxeGrid({ formOptions, gridOptions });
|
||
|
||
const editRow: Record<string, any> = ref({});
|
||
// 声明文件变量,用于存储选择的文件
|
||
let selectedFile: File | null = null;
|
||
|
||
// 设置文件选择回调
|
||
setFileSelectedCallback((file) => {
|
||
selectedFile = file;
|
||
});
|
||
const [UserModal, userModalApi] = useVbenModal({
|
||
draggable: true,
|
||
footer: true,
|
||
showCancelButton: true,
|
||
showConfirmButton: true,
|
||
onConfirm: submit,
|
||
onBeforeClose: () => {
|
||
// 只在确认提交后重置,而不是每次关闭都重置
|
||
return true;
|
||
},
|
||
onOpen: () => {
|
||
// 重置文件选择
|
||
selectedFile = null;
|
||
},
|
||
onOpenChange: (isOpen: boolean) => {
|
||
if (isOpen && editRow.value.id) {
|
||
// 编辑模式下,模态框打开后设置表单值
|
||
nextTick(() => {
|
||
editFormApi.setValues({ ...editRow.value });
|
||
});
|
||
}
|
||
},
|
||
onCancel: () => {
|
||
// 取消时也重置文件选择
|
||
selectedFile = null;
|
||
// 关闭模态框
|
||
userModalApi.close();
|
||
},
|
||
});
|
||
|
||
const [AddForm, addFormApi] = useVbenForm({
|
||
// 默认展开
|
||
collapsed: false,
|
||
// 所有表单项共用,可单独在表单内覆盖
|
||
commonConfig: {
|
||
labelWidth: 110,
|
||
componentProps: {
|
||
class: 'w-4/5',
|
||
},
|
||
},
|
||
layout: 'horizontal',
|
||
schema: addProductFormSchema.value,
|
||
showCollapseButton: false,
|
||
showDefaultActions: false,
|
||
wrapperClass: 'grid-cols-2',
|
||
});
|
||
|
||
const [EditForm, editFormApi] = useVbenForm({
|
||
// 默认展开
|
||
collapsed: false,
|
||
// 所有表单项共用,可单独在表单内覆盖
|
||
commonConfig: {
|
||
labelWidth: 110,
|
||
componentProps: {
|
||
class: 'w-4/5',
|
||
},
|
||
},
|
||
// 提交函数
|
||
layout: 'horizontal',
|
||
schema: editProductFormSchemaEdit.value,
|
||
showCollapseButton: false,
|
||
showDefaultActions: false,
|
||
wrapperClass: 'grid-cols-2',
|
||
});
|
||
|
||
// 新增和编辑提交的逻辑
|
||
async function submit() {
|
||
const isEdit = !!editRow.value.id;
|
||
const formApi = isEdit ? editFormApi : addFormApi;
|
||
const api = isEdit
|
||
? postOneNetProductModifyAsync
|
||
: postOneNetProductInsertAsync;
|
||
const { valid } = await formApi.validate();
|
||
if (!valid) return;
|
||
|
||
const formValues = await formApi.getValues();
|
||
|
||
// 提交前校验
|
||
if (!formValues.deviceThingModelFileName) {
|
||
Message.error('请选择设备模型文件');
|
||
return;
|
||
}
|
||
|
||
// 如果有文件需要上传,先上传
|
||
if (selectedFile) {
|
||
try {
|
||
userModalApi.setState({ loading: true, confirmLoading: true });
|
||
const result = await postFilesUpload({ body: { files: [selectedFile] } });
|
||
if (result.status === 204 || result.status === 200) {
|
||
const fileInfo = result.data?.[0];
|
||
if (fileInfo && fileInfo.id) {
|
||
formValues.deviceThingModelFileId = fileInfo.id;
|
||
// 设置文件名
|
||
formValues.deviceThingModelFileName =
|
||
fileInfo.fileName || selectedFile.name;
|
||
} else {
|
||
Message.error('文件上传成功但未获取到文件ID');
|
||
userModalApi.setState({ loading: false, confirmLoading: false });
|
||
return;
|
||
}
|
||
} else {
|
||
Message.error('文件上传失败');
|
||
userModalApi.setState({ loading: false, confirmLoading: false });
|
||
return;
|
||
}
|
||
} catch {
|
||
Message.error('文件上传失败');
|
||
userModalApi.setState({ loading: false, confirmLoading: false });
|
||
return;
|
||
}
|
||
}
|
||
|
||
// 清空全局变量,防止下次误用
|
||
selectedFile = null;
|
||
|
||
// 继续后续表单提交逻辑
|
||
|
||
const fetchParams: any = isEdit
|
||
? {
|
||
id: editRow.value.id,
|
||
...formValues,
|
||
}
|
||
: {
|
||
...formValues,
|
||
};
|
||
|
||
try {
|
||
const resp = await api({ body: fetchParams });
|
||
if (resp.data) {
|
||
Message.success(
|
||
editRow.value.id ? $t('common.editSuccess') : $t('common.addSuccess'),
|
||
);
|
||
userModalApi.close();
|
||
editRow.value = {};
|
||
gridApi.reload();
|
||
} else {
|
||
Message.error(
|
||
editRow.value.id ? $t('common.editFail') : $t('common.addFail'),
|
||
);
|
||
}
|
||
} finally {
|
||
userModalApi.setState({ loading: false, confirmLoading: false });
|
||
}
|
||
}
|
||
|
||
async function onEdit(record: any) {
|
||
editRow.value = record;
|
||
userModalApi.open();
|
||
// 重置文件选择状态
|
||
selectedFile = null;
|
||
}
|
||
|
||
const openAddModal = async () => {
|
||
editRow.value = {};
|
||
userModalApi.open();
|
||
// 重置文件选择状态
|
||
selectedFile = null;
|
||
};
|
||
|
||
// 删除函数
|
||
async function onDel(record: any) {
|
||
try {
|
||
const resp = await postOneNetProductDeleteAsync({
|
||
body: { id: record.id },
|
||
});
|
||
if (resp.data) {
|
||
Message.success($t('common.deleteSuccess'));
|
||
// 重置文件选择
|
||
selectedFile = null;
|
||
gridApi.reload();
|
||
} else {
|
||
Message.error($t('common.deleteFail'));
|
||
}
|
||
} catch {
|
||
Message.error($t('common.deleteFail'));
|
||
}
|
||
}
|
||
|
||
// 下载文件函数
|
||
async function onDownloadFile(record: any) {
|
||
if (!record.deviceThingModelFileId) {
|
||
Message.error('文件ID不存在,无法下载');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const { data } = await postFilesDownload({
|
||
body: { id: record.deviceThingModelFileId },
|
||
responseType: 'blob',
|
||
});
|
||
const url = window.URL.createObjectURL(new Blob([data as Blob]));
|
||
const link = document.createElement('a');
|
||
link.href = url;
|
||
link.setAttribute(
|
||
'download',
|
||
record.deviceThingModelFileName || 'device-model-file',
|
||
);
|
||
document.body.append(link);
|
||
link.click();
|
||
link.remove();
|
||
window.URL.revokeObjectURL(url);
|
||
Message.success('文件下载成功');
|
||
} catch {
|
||
Message.error('文件下载失败');
|
||
}
|
||
}
|
||
|
||
// 状态更改函数
|
||
async function onStatusChange(record: any) {
|
||
try {
|
||
const resp = await postOneNetProductProductStatusChangeAsync({
|
||
body: {
|
||
id: record.id,
|
||
enabled: !record.isEnabled,
|
||
},
|
||
});
|
||
if (resp.data) {
|
||
Message.success(record.isEnabled ? '禁用成功' : '启用成功');
|
||
gridApi.reload();
|
||
} else {
|
||
Message.error(record.isEnabled ? '禁用失败' : '启用失败');
|
||
}
|
||
} catch {
|
||
Message.error(record.isEnabled ? '禁用失败' : '启用失败');
|
||
}
|
||
}
|
||
|
||
// 设备管理函数
|
||
function onDeviceManagement(record: any) {
|
||
console.log('设备管理按钮被点击', record);
|
||
// 跳转到设备管理页面,传递平台类型和平台产品ID作为参数
|
||
router.push({
|
||
path: '/devicemanagement/deviceinfo',
|
||
query: {
|
||
ioTPlatform: '2', // OneNET平台类型为2
|
||
ioTPlatformDeviceOpenInfo: record.ioTPlatformProductId, // 平台产品ID
|
||
productName: record.productName,
|
||
},
|
||
});
|
||
}
|
||
|
||
// 物模型管理函数
|
||
function onThingModelManagement(record: any) {
|
||
console.log('物模型管理按钮被点击', record);
|
||
// 跳转到物模型管理页面,传递平台类型和平台产品ID作为参数
|
||
router.push({
|
||
path: '/thingmodelinfo/ioTPlatformThingModelInfo',
|
||
query: {
|
||
productId: record.ioTPlatformProductId, // 平台产品ID
|
||
productName: record.productName,
|
||
ioTPlatform: '2', // OneNET平台类型为2
|
||
},
|
||
});
|
||
}
|
||
</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'],
|
||
},
|
||
]" />
|
||
</template>
|
||
|
||
<template #isEnable="{ row }">
|
||
<component :is="h(Tag, { color: row.isEnabled ? 'green' : 'red' }, () =>
|
||
row.isEnabled ? $t('common.yes') : $t('common.no'),
|
||
)
|
||
" />
|
||
</template>
|
||
|
||
<template #deviceThingModelFileName="{ row }">
|
||
<a v-if="row.deviceThingModelFileName && row.deviceThingModelFileId" @click="onDownloadFile(row)"
|
||
style="color: #1890ff; text-decoration: underline; cursor: pointer">
|
||
{{ row.deviceThingModelFileName }}
|
||
</a>
|
||
<span v-else>{{ row.deviceThingModelFileName || '-' }}</span>
|
||
</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('abp.deviceInfos.deviceInfoManage'),
|
||
type: 'link',
|
||
size: 'small',
|
||
onClick: onDeviceManagement.bind(null, row),
|
||
},
|
||
{
|
||
label: $t('abp.deviceInfos.thingModelInfoManage'),
|
||
type: 'link',
|
||
size: 'small',
|
||
onClick: onThingModelManagement.bind(null, row),
|
||
}
|
||
]" :drop-down-actions="[
|
||
{
|
||
label: row.isEnabled ? $t('common.disabled') : $t('common.enabled'),
|
||
icon: 'ant-design:edit-filled',
|
||
type: 'primary',
|
||
danger: row.isEnabled,
|
||
size: 'small',
|
||
auth: ['AbpIdentity.Users.Update'],
|
||
popConfirm: {
|
||
title: `确定要${row.isEnabled ? $t('common.disabled') : $t('common.enabled')}该产品吗?`,
|
||
confirm: onStatusChange.bind(null, row),
|
||
},
|
||
},
|
||
{
|
||
label: $t('common.delete'),
|
||
icon: 'ant-design:delete-outlined',
|
||
type: 'primary',
|
||
popConfirm: {
|
||
title: $t('common.askConfirmDelete'),
|
||
confirm: onDel.bind(null, row),
|
||
},
|
||
},
|
||
]" />
|
||
</template>
|
||
</Grid>
|
||
<UserModal :title="editRow.id ? $t('common.edit') : $t('common.add')" class="w-[800px]">
|
||
<component :is="editRow.id ? EditForm : AddForm" />
|
||
</UserModal>
|
||
</Page>
|
||
</template>
|