fix:【iot 物联网】linter 报错

This commit is contained in:
YunaiV
2025-10-10 20:26:17 +08:00
parent b6fee5c05b
commit f740461c2a
107 changed files with 7161 additions and 5905 deletions

View File

@@ -8,10 +8,10 @@ import { handleTree } from '@vben/utils';
import { message } from 'ant-design-vue';
import { z } from '#/adapter/form';
import {
deleteProductCategory,
import {
deleteProductCategory,
getProductCategoryPage,
getSimpleProductCategoryList
getSimpleProductCategoryList,
} from '#/api/iot/product/category';
import { $t } from '#/locales';
@@ -162,7 +162,10 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
}
/** 删除分类 */
export async function handleDeleteCategory(row: IotProductCategoryApi.ProductCategory, onSuccess?: () => void) {
export async function handleDeleteCategory(
row: IotProductCategoryApi.ProductCategory,
onSuccess?: () => void,
) {
const hideLoading = message.loading({
content: $t('ui.actionMessage.deleting', [row.name]),
duration: 0,

View File

@@ -7,11 +7,11 @@ import { Page, useVbenModal } from '@vben/common-ui';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { $t } from '#/locales';
import {
handleDeleteCategory,
import {
handleDeleteCategory,
queryProductCategoryList,
useGridColumns,
useGridFormSchema
useGridColumns,
useGridFormSchema,
} from './data';
import Form from './modules/ProductCategoryForm.vue';
@@ -66,7 +66,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
},
toolbarConfig: {
refresh: true,
search:true,
search: true,
},
treeConfig: {
parentField: 'parentId',
@@ -95,7 +95,6 @@ const [Grid, gridApi] = useVbenVxeGrid({
icon: ACTION_ICON.ADD,
onClick: handleCreate,
},
]"
/>
</template>

View File

@@ -11,10 +11,10 @@ import { message } from 'ant-design-vue';
import { z } from '#/adapter/form';
import { getSimpleProductCategoryList } from '#/api/iot/product/category';
import {
deleteProduct,
exportProduct,
getProductPage
import {
deleteProduct,
exportProduct,
getProductPage,
} from '#/api/iot/product/product';
/** 新增/修改产品的表单 */

View File

@@ -4,17 +4,15 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';
import { Button, Card, Image, Input, Space } from 'ant-design-vue';
import { Page, useVbenModal } from '@vben/common-ui';
import { IconifyIcon } from '@vben/icons';
import { Button, Card, Image, Input, Space } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { $t } from '#/locales';
import ProductForm from './modules/ProductForm.vue';
// @ts-ignore
import ProductCardView from './modules/ProductCardView.vue';
import {
import {
getCategoryName,
handleDeleteProduct,
handleExportProduct,
@@ -23,12 +21,15 @@ import {
useGridColumns,
useImagePreview,
} from './data';
// @ts-ignore
import ProductCardView from './modules/ProductCardView.vue';
import ProductForm from './modules/ProductForm.vue';
defineOptions({ name: 'IoTProduct' });
const router = useRouter();
const categoryList = ref<any[]>([]);
const viewMode = ref<'list' | 'card'>('card');
const viewMode = ref<'card' | 'list'>('card');
const cardViewRef = ref();
// 搜索参数
@@ -150,17 +151,17 @@ onMounted(() => {
<template>
<Page auto-content-height>
<FormModal @success="handleRefresh" />
<!-- 统一搜索工具栏 -->
<Card :body-style="{ padding: '16px' }" class="mb-4">
<!-- 搜索表单 -->
<div class="flex items-center gap-3 mb-3">
<div class="mb-3 flex items-center gap-3">
<Input
v-model:value="searchParams.name"
placeholder="请输入产品名称"
allow-clear
style="width: 200px"
@pressEnter="handleSearch"
@press-enter="handleSearch"
>
<template #prefix>
<span class="text-gray-400">产品名称</span>
@@ -171,7 +172,7 @@ onMounted(() => {
placeholder="请输入产品标识"
allow-clear
style="width: 200px"
@pressEnter="handleSearch"
@press-enter="handleSearch"
>
<template #prefix>
<span class="text-gray-400">ProductKey</span>
@@ -199,7 +200,7 @@ onMounted(() => {
导出
</Button>
</Space>
<!-- 视图切换 -->
<Space :size="4">
<Button

View File

@@ -1,6 +1,10 @@
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { DICT_TYPE } from '@vben/constants';
import { getDictLabel } from '@vben/hooks';
import { IconifyIcon } from '@vben/icons';
import {
Button,
Card,
@@ -12,14 +16,21 @@ import {
Tag,
Tooltip,
} from 'ant-design-vue';
import { DICT_TYPE } from '@vben/constants';
import { getDictLabel } from '@vben/hooks';
import { IconifyIcon } from '@vben/icons';
import { getProductPage } from '#/api/iot/product/product';
defineOptions({ name: 'ProductCardView' });
const props = defineProps<Props>();
const emit = defineEmits<{
create: [];
delete: [row: any];
detail: [productId: number];
edit: [row: any];
thingModel: [productId: number];
}>();
interface Props {
categoryList: any[];
searchParams?: {
@@ -28,16 +39,6 @@ interface Props {
};
}
const props = defineProps<Props>();
const emit = defineEmits<{
create: [];
edit: [row: any];
delete: [row: any];
detail: [productId: number];
thingModel: [productId: number];
}>();
const loading = ref(false);
const list = ref<any[]>([]);
const total = ref(0);
@@ -88,7 +89,7 @@ onMounted(() => {
});
// 暴露方法供父组件调用
defineExpose({
defineExpose({
reload: getList,
search: () => {
queryParams.value.pageNo = 1;
@@ -111,42 +112,57 @@ defineExpose({
:lg="6"
class="mb-4"
>
<Card
:body-style="{ padding: '20px' }"
class="product-card h-full"
>
<Card :body-style="{ padding: '20px' }" class="product-card h-full">
<!-- 顶部标题区域 -->
<div class="flex items-start mb-4">
<div class="mb-4 flex items-start">
<div class="product-icon">
<IconifyIcon icon="ant-design:inbox-outlined" class="text-[32px]" />
<IconifyIcon
icon="ant-design:inbox-outlined"
class="text-[32px]"
/>
</div>
<div class="ml-3 flex-1 min-w-0">
<div class="ml-3 min-w-0 flex-1">
<div class="product-title">{{ item.name }}</div>
</div>
</div>
<!-- 内容区域 -->
<div class="flex items-start mb-4">
<div class="flex-1 info-list">
<div class="mb-4 flex items-start">
<div class="info-list flex-1">
<div class="info-item">
<span class="info-label">产品分类</span>
<span class="info-value text-primary">{{ getCategoryName(item.categoryId) }}</span>
<span class="info-value text-primary">{{
getCategoryName(item.categoryId)
}}</span>
</div>
<div class="info-item">
<span class="info-label">产品类型</span>
<Tag :color="getDeviceTypeColor(item.deviceType)" class="m-0 info-tag">
{{ getDictLabel(DICT_TYPE.IOT_PRODUCT_DEVICE_TYPE, item.deviceType) }}
<Tag
:color="getDeviceTypeColor(item.deviceType)"
class="info-tag m-0"
>
{{
getDictLabel(
DICT_TYPE.IOT_PRODUCT_DEVICE_TYPE,
item.deviceType,
)
}}
</Tag>
</div>
<div class="info-item">
<span class="info-label">产品标识</span>
<Tooltip :title="item.productKey || item.id" placement="top">
<span class="info-value product-key">{{ item.productKey || item.id }}</span>
<span class="info-value product-key">{{
item.productKey || item.id
}}</span>
</Tooltip>
</div>
</div>
<div class="product-3d-icon">
<IconifyIcon icon="ant-design:box-plot-outlined" class="text-[80px]" />
<IconifyIcon
icon="ant-design:box-plot-outlined"
class="text-[80px]"
/>
</div>
</div>
@@ -173,7 +189,10 @@ defineExpose({
class="action-btn action-btn-model"
@click="emit('thingModel', item.id)"
>
<IconifyIcon icon="ant-design:apartment-outlined" class="mr-1" />
<IconifyIcon
icon="ant-design:apartment-outlined"
class="mr-1"
/>
物模型
</Button>
<Popconfirm
@@ -374,4 +393,3 @@ defineExpose({
}
}
</style>

View File

@@ -1,10 +1,17 @@
<script setup lang="ts">
import type { IotProductApi } from '#/api/iot/product/product';
import { computed, ref } from 'vue';
import { message } from 'ant-design-vue';
import { useVbenForm, useVbenModal } from '@vben/common-ui';
import { createProduct, getProduct, updateProduct, type IotProductApi } from '#/api/iot/product/product';
import { message } from 'ant-design-vue';
import {
createProduct,
getProduct,
updateProduct,
} from '#/api/iot/product/product';
import { $t } from '#/locales';
import { useFormSchema } from '../data';

View File

@@ -1,20 +1,18 @@
<!-- IoT 产品选择器使用弹窗展示 -->
<script setup lang="ts">
import type { IotProductApi } from '#/api/iot/product/product';
import { reactive, ref } from 'vue';
import { message } from 'ant-design-vue';
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getProductPage } from '#/api/iot/product/product';
import type { IotProductApi } from '#/api/iot/product/product';
defineOptions({ name: 'IoTProductTableSelect' });
interface Props {
multiple?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
multiple: false,
});
@@ -23,6 +21,10 @@ const emit = defineEmits<{
success: [product: IotProductApi.Product | IotProductApi.Product[]];
}>();
interface Props {
multiple?: boolean;
}
const [Modal, modalApi] = useVbenModal({
title: '产品选择器',
onConfirm: handleConfirm,

View File

@@ -1,11 +1,12 @@
<script setup lang="ts">
import type { IotProductApi } from '#/api/iot/product/product';
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import { message } from 'ant-design-vue';
import { updateProductStatus } from '#/api/iot/product/product';
import type { IotProductApi } from '#/api/iot/product/product';
import ProductForm from '../ProductForm.vue';
@@ -37,7 +38,10 @@ const copyToClipboard = async (text: string) => {
/** 跳转到设备管理 */
const goToDeviceList = (productId: number) => {
router.push({ path: '/iot/device/device', query: { productId: String(productId) } });
router.push({
path: '/iot/device/device',
query: { productId: String(productId) },
});
};
/** 打开编辑表单 */
@@ -102,12 +106,18 @@ const confirmUnpublish = async (id: number) => {
<a-descriptions :column="1">
<a-descriptions-item label="ProductKey">
{{ product.productKey }}
<a-button size="small" class="ml-2" @click="copyToClipboard(product.productKey || '')">
<a-button
size="small"
class="ml-2"
@click="copyToClipboard(product.productKey || '')"
>
复制
</a-button>
</a-descriptions-item>
<a-descriptions-item label="设备总数">
<span class="ml-5 mr-2">{{ product.deviceCount ?? '加载中...' }}</span>
<span class="ml-5 mr-2">{{
product.deviceCount ?? '加载中...'
}}</span>
<a-button size="small" @click="goToDeviceList(product.id!)">
前往管理
</a-button>

View File

@@ -1,9 +1,10 @@
<script setup lang="ts">
import type { IotProductApi } from '#/api/iot/product/product';
import { DICT_TYPE } from '@vben/constants';
import { DictTag } from '#/components/dict-tag';
import type { IotProductApi } from '#/api/iot/product/product';
import { DeviceTypeEnum } from '#/api/iot/product/product';
import { DictTag } from '#/components/dict-tag';
interface Props {
product: IotProductApi.Product;
@@ -28,7 +29,10 @@ const formatDate = (date?: Date | string) => {
{{ product.categoryName || '-' }}
</a-descriptions-item>
<a-descriptions-item label="设备类型">
<DictTag :type="DICT_TYPE.IOT_PRODUCT_DEVICE_TYPE" :value="product.deviceType" />
<DictTag
:type="DICT_TYPE.IOT_PRODUCT_DEVICE_TYPE"
:value="product.deviceType"
/>
</a-descriptions-item>
<a-descriptions-item label="定位类型">
{{ product.locationType ?? '-' }}
@@ -43,7 +47,11 @@ const formatDate = (date?: Date | string) => {
<DictTag :type="DICT_TYPE.COMMON_STATUS" :value="product.status" />
</a-descriptions-item>
<a-descriptions-item
v-if="[DeviceTypeEnum.DEVICE, DeviceTypeEnum.GATEWAY].includes(product.deviceType!)"
v-if="
[DeviceTypeEnum.DEVICE, DeviceTypeEnum.GATEWAY].includes(
product.deviceType!,
)
"
label="联网方式"
>
<DictTag :type="DICT_TYPE.IOT_NET_TYPE" :value="product.netType" />

View File

@@ -1,17 +1,19 @@
<script setup lang="ts">
import type { IotProductApi } from '#/api/iot/product/product';
import { onMounted, provide, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { message } from 'ant-design-vue';
import { Page } from '@vben/common-ui';
import { getProduct } from '#/api/iot/product/product';
import type { IotProductApi } from '#/api/iot/product/product';
import { message } from 'ant-design-vue';
import { getDeviceCount } from '#/api/iot/device/device';
import { getProduct } from '#/api/iot/product/product';
import IoTProductThingModel from '#/views/iot/thingmodel/index.vue';
import ProductDetailsHeader from './ProductDetailsHeader.vue';
import ProductDetailsInfo from './ProductDetailsInfo.vue';
import IoTProductThingModel from '#/views/iot/thingmodel/index.vue';
defineOptions({ name: 'IoTProductDetail' });
@@ -43,7 +45,12 @@ const getDeviceCountData = async (productId: number) => {
try {
return await getDeviceCount(productId);
} catch (error) {
console.error('Error fetching device count:', error, 'productId:', productId);
console.error(
'Error fetching device count:',
error,
'productId:',
productId,
);
return 0;
}
};
@@ -55,15 +62,15 @@ onMounted(async () => {
router.back();
return;
}
await getProductData(id);
// 处理 tab 参数
const { tab } = route.query;
if (tab) {
activeTab.value = tab as string;
}
// 查询设备数量
if (product.value.id) {
product.value.deviceCount = await getDeviceCountData(product.value.id);
@@ -84,7 +91,10 @@ onMounted(async () => {
<ProductDetailsInfo v-if="activeTab === 'info'" :product="product" />
</a-tab-pane>
<a-tab-pane key="thingModel" tab="物模型(功能定义)">
<IoTProductThingModel v-if="activeTab === 'thingModel'" :product-id="id" />
<IoTProductThingModel
v-if="activeTab === 'thingModel'"
:product-id="id"
/>
</a-tab-pane>
</a-tabs>
</Page>