fix(web-antdv-next): 修复Form.Item、Descriptions.Item 报错提示

pull/359/head
XuZhiqiang 2026-06-06 12:00:51 +08:00
parent 1123f00795
commit 4f66adb999
37 changed files with 430 additions and 437 deletions

View File

@ -6,7 +6,7 @@ import { useRouter } from 'vue-router';
import { useVbenModal } from '@vben/common-ui';
import { Button, Card, Descriptions, message } from 'antdv-next';
import { Button, Card, Descriptions, DescriptionsItem, message } from 'antdv-next';
import DeviceForm from '../../modules/form.vue';
@ -75,15 +75,15 @@ function openEditForm(row: IotDeviceApi.Device) {
<Card class="mt-4">
<Descriptions :column="2">
<Descriptions.Item label="产品">
<DescriptionsItem label="产品">
<a
class="cursor-pointer text-blue-600"
@click="goToProductDetail(product.id)"
>
{{ product.name }}
</a>
</Descriptions.Item>
<Descriptions.Item label="ProductKey">
</DescriptionsItem>
<DescriptionsItem label="ProductKey">
{{ product.productKey }}
<Button
class="ml-2"
@ -92,7 +92,7 @@ function openEditForm(row: IotDeviceApi.Device) {
>
复制
</Button>
</Descriptions.Item>
</DescriptionsItem>
</Descriptions>
</Card>
</div>

View File

@ -12,7 +12,9 @@ import {
Button,
Card,
Descriptions,
DescriptionsItem,
Form,
FormItem,
Input,
message,
Modal,
@ -38,7 +40,7 @@ const mapDialogRef = ref<InstanceType<typeof MapDialog>>();
/** 是否有位置信息(合法经纬度 0 不应视为空) */
const hasLocation = computed(() => {
return props.device.longitude != null && props.device.latitude != null;
return props.device.longitude !== null && props.device.latitude !== null;
});
/** 打开地图弹窗 */
@ -77,40 +79,40 @@ function handleAuthInfoDialogClose() {
<div>
<Card title="设备信息">
<Descriptions :column="3" bordered size="small">
<Descriptions.Item label="产品名称">
<DescriptionsItem label="产品名称">
{{ product.name }}
</Descriptions.Item>
<Descriptions.Item label="ProductKey">
</DescriptionsItem>
<DescriptionsItem label="ProductKey">
{{ product.productKey }}
</Descriptions.Item>
<Descriptions.Item label="设备类型">
</DescriptionsItem>
<DescriptionsItem label="设备类型">
<DictTag
:type="DICT_TYPE.IOT_PRODUCT_DEVICE_TYPE"
:value="product.deviceType"
/>
</Descriptions.Item>
<Descriptions.Item label="DeviceName">
</DescriptionsItem>
<DescriptionsItem label="DeviceName">
{{ device.deviceName }}
</Descriptions.Item>
<Descriptions.Item label="备注名称">
</DescriptionsItem>
<DescriptionsItem label="备注名称">
{{ device.nickname || '--' }}
</Descriptions.Item>
<Descriptions.Item label="当前状态">
</DescriptionsItem>
<DescriptionsItem label="当前状态">
<DictTag :type="DICT_TYPE.IOT_DEVICE_STATE" :value="device.state" />
</Descriptions.Item>
<Descriptions.Item label="创建时间">
</DescriptionsItem>
<DescriptionsItem label="创建时间">
{{ formatDateTime(device.createTime) }}
</Descriptions.Item>
<Descriptions.Item label="激活时间">
</DescriptionsItem>
<DescriptionsItem label="激活时间">
{{ formatDateTime(device.activeTime) }}
</Descriptions.Item>
<Descriptions.Item label="最后上线时间">
</DescriptionsItem>
<DescriptionsItem label="最后上线时间">
{{ formatDateTime(device.onlineTime) }}
</Descriptions.Item>
<Descriptions.Item label="最后离线时间">
</DescriptionsItem>
<DescriptionsItem label="最后离线时间">
{{ formatDateTime(device.offlineTime) }}
</Descriptions.Item>
<Descriptions.Item label="设备位置">
</DescriptionsItem>
<DescriptionsItem label="设备位置">
<template v-if="hasLocation">
<span class="mr-2">
{{ device.longitude }}, {{ device.latitude }}
@ -121,12 +123,12 @@ function handleAuthInfoDialogClose() {
</Button>
</template>
<span v-else class="text-gray-400">暂无位置信息</span>
</Descriptions.Item>
<Descriptions.Item label="MQTT 连接参数">
</DescriptionsItem>
<DescriptionsItem label="MQTT 连接参数">
<Button size="small" type="link" @click="handleAuthInfoDialogOpen">
查看
</Button>
</Descriptions.Item>
</DescriptionsItem>
</Descriptions>
</Card>
@ -138,7 +140,7 @@ function handleAuthInfoDialogClose() {
width="640px"
>
<Form :label-col="{ span: 6 }">
<Form.Item label="clientId">
<FormItem label="clientId">
<Input.Group compact>
<Input
v-model:value="authInfo.clientId"
@ -149,8 +151,8 @@ function handleAuthInfoDialogClose() {
<IconifyIcon icon="lucide:copy" />
</Button>
</Input.Group>
</Form.Item>
<Form.Item label="username">
</FormItem>
<FormItem label="username">
<Input.Group compact>
<Input
v-model:value="authInfo.username"
@ -161,8 +163,8 @@ function handleAuthInfoDialogClose() {
<IconifyIcon icon="lucide:copy" />
</Button>
</Input.Group>
</Form.Item>
<Form.Item label="password">
</FormItem>
<FormItem label="password">
<Input.Group compact>
<Input
v-model:value="authInfo.password"
@ -182,7 +184,7 @@ function handleAuthInfoDialogClose() {
<IconifyIcon icon="lucide:copy" />
</Button>
</Input.Group>
</Form.Item>
</FormItem>
</Form>
<div class="mt-4 text-right">
<Button @click="handleAuthInfoDialogClose"></Button>

View File

@ -11,6 +11,7 @@ import {
Button,
Card,
Descriptions,
DescriptionsItem,
message,
Popconfirm,
} from 'antdv-next';
@ -135,7 +136,7 @@ async function handleSyncPropertyTable(product: IotProductApi.Product) {
<Card class="mt-4">
<Descriptions :column="1">
<Descriptions.Item label="ProductKey">
<DescriptionsItem label="ProductKey">
{{ product.productKey }}
<Button
class="ml-2"
@ -144,15 +145,15 @@ async function handleSyncPropertyTable(product: IotProductApi.Product) {
>
复制
</Button>
</Descriptions.Item>
<Descriptions.Item label="设备总数">
</DescriptionsItem>
<DescriptionsItem label="设备总数">
<span class="ml-5 mr-2">
{{ product.deviceCount ?? '加载中...' }}
</span>
<Button size="small" @click="goToDeviceList(product.id!)">
前往管理
</Button>
</Descriptions.Item>
</DescriptionsItem>
</Descriptions>
</Card>
</div>

View File

@ -5,7 +5,7 @@ import { ref } from 'vue';
import { DeviceTypeEnum, DICT_TYPE } from '@vben/constants';
import { Button, Card, Descriptions, message } from 'antdv-next';
import { Button, Card, Descriptions, DescriptionsItem, message } from 'antdv-next';
import { DictTag } from '#/components/dict-tag';
@ -44,37 +44,37 @@ async function copyToClipboard(text: string) {
<template>
<Card title="产品信息">
<Descriptions :column="3" bordered size="small">
<Descriptions.Item label="产品名称">
<DescriptionsItem label="产品名称">
{{ product.name }}
</Descriptions.Item>
<Descriptions.Item label="所属分类">
</DescriptionsItem>
<DescriptionsItem label="所属分类">
{{ product.categoryName || '-' }}
</Descriptions.Item>
<Descriptions.Item label="设备类型">
</DescriptionsItem>
<DescriptionsItem label="设备类型">
<DictTag
:type="DICT_TYPE.IOT_PRODUCT_DEVICE_TYPE"
:value="product.deviceType"
/>
</Descriptions.Item>
<Descriptions.Item label="创建时间">
</DescriptionsItem>
<DescriptionsItem label="创建时间">
{{ formatDate(product.createTime) }}
</Descriptions.Item>
<Descriptions.Item label="协议类型">
</DescriptionsItem>
<DescriptionsItem label="协议类型">
<DictTag
:type="DICT_TYPE.IOT_PROTOCOL_TYPE"
:value="product.protocolType"
/>
</Descriptions.Item>
<Descriptions.Item label="序列化类型">
</DescriptionsItem>
<DescriptionsItem label="序列化类型">
<DictTag
:type="DICT_TYPE.IOT_SERIALIZE_TYPE"
:value="product.serializeType"
/>
</Descriptions.Item>
<Descriptions.Item label="产品状态">
</DescriptionsItem>
<DescriptionsItem label="产品状态">
<DictTag :type="DICT_TYPE.IOT_PRODUCT_STATUS" :value="product.status" />
</Descriptions.Item>
<Descriptions.Item
</DescriptionsItem>
<DescriptionsItem
v-if="
(
[DeviceTypeEnum.DEVICE, DeviceTypeEnum.GATEWAY] as number[]
@ -83,8 +83,8 @@ async function copyToClipboard(text: string) {
label="联网方式"
>
<DictTag :type="DICT_TYPE.IOT_NET_TYPE" :value="product.netType" />
</Descriptions.Item>
<Descriptions.Item label="产品密钥">
</DescriptionsItem>
<DescriptionsItem label="产品密钥">
<span v-if="showProductSecret">{{ product.productSecret }}</span>
<span v-else>********</span>
<Button class="ml-2" size="small" @click="toggleProductSecretVisible">
@ -98,13 +98,13 @@ async function copyToClipboard(text: string) {
>
复制
</Button>
</Descriptions.Item>
<Descriptions.Item label="动态注册">
</DescriptionsItem>
<DescriptionsItem label="动态注册">
{{ product.registerEnabled ? '已开启' : '未开启' }}
</Descriptions.Item>
<Descriptions.Item :span="3" label="产品描述">
</DescriptionsItem>
<DescriptionsItem :span="3" label="产品描述">
{{ product.description || '-' }}
</Descriptions.Item>
</DescriptionsItem>
</Descriptions>
</Card>
</template>

View File

@ -5,7 +5,7 @@ import { IconifyIcon } from '@vben/icons';
import { isEmpty } from '@vben/utils';
import { useClipboard, useVModel } from '@vueuse/core';
import { Button, Form, Input, message } from 'antdv-next';
import { Button, Form, FormItem, Input, message } from 'antdv-next';
import { IotDataSinkTypeEnum } from '#/api/iot/rule/data/sink';
@ -67,7 +67,7 @@ onMounted(() => {
</script>
<template>
<Form.Item
<FormItem
:name="['config', 'jdbcUrl']"
:rules="[
{ required: true, message: 'JDBC 连接地址不能为空', trigger: 'blur' },
@ -78,15 +78,15 @@ onMounted(() => {
v-model:value="config.jdbcUrl"
placeholder="请输入 JDBC 连接地址jdbc:mysql://localhost:3306/iot_data"
/>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'username']"
:rules="[{ required: true, message: '用户名不能为空', trigger: 'blur' }]"
label="用户名"
>
<Input v-model:value="config.username" placeholder="请输入数据库用户名" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'password']"
:rules="[{ required: true, message: '密码不能为空', trigger: 'blur' }]"
label="密码"
@ -95,8 +95,8 @@ onMounted(() => {
v-model:value="config.password"
placeholder="请输入数据库密码"
/>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'tableName']"
:rules="[{ required: true, message: '目标表名不能为空', trigger: 'blur' }]"
label="目标表名"
@ -115,7 +115,7 @@ onMounted(() => {
{{ showSqlTip ? '收起表结构提示' : '查看表结构提示' }}
</Button>
</div>
</Form.Item>
</FormItem>
<div
v-if="showSqlTip"
class="mt-2 overflow-hidden rounded border border-gray-200 dark:border-gray-700"

View File

@ -5,7 +5,7 @@ import { computed, onMounted, ref, watch } from 'vue';
import { isEmpty } from '@vben/utils';
import { useVModel } from '@vueuse/core';
import { Form, Input, Select } from 'antdv-next';
import { FormItem, Input, Select } from 'antdv-next';
import { IotDataSinkTypeEnum } from '#/api/iot/rule/data/sink';
@ -60,7 +60,7 @@ onMounted(() => {
</script>
<template>
<Form.Item
<FormItem
:name="['config', 'url']"
:rules="[{ required: true, message: '请求地址不能为空', trigger: 'blur' }]"
label="请求地址"
@ -73,8 +73,8 @@ onMounted(() => {
</Select>
</template>
</Input>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'method']"
:rules="[
{ required: true, message: '请求方法不能为空', trigger: 'change' },
@ -87,18 +87,18 @@ onMounted(() => {
<Select.Option value="PUT">PUT</Select.Option>
<Select.Option value="DELETE">DELETE</Select.Option>
</Select>
</Form.Item>
<Form.Item label="请求头">
</FormItem>
<FormItem label="请求头">
<KeyValueEditor v-model="config.headers" add-button-text="" />
</Form.Item>
<Form.Item label="请求参数">
</FormItem>
<FormItem label="请求参数">
<KeyValueEditor v-model="config.query" add-button-text="" />
</Form.Item>
<Form.Item label="请求体">
</FormItem>
<FormItem label="请求体">
<Input.TextArea
v-model:value="config.body"
placeholder="请输入内容"
:rows="4"
/>
</Form.Item>
</FormItem>
</template>

View File

@ -4,7 +4,7 @@ import { onMounted } from 'vue';
import { isEmpty } from '@vben/utils';
import { useVModel } from '@vueuse/core';
import { Form, Input, Switch } from 'antdv-next';
import { FormItem, Input, Switch } from 'antdv-next';
import { IotDataSinkTypeEnum } from '#/api/iot/rule/data/sink';
@ -28,7 +28,7 @@ onMounted(() => {
</script>
<template>
<Form.Item
<FormItem
:name="['config', 'bootstrapServers']"
:rules="[{ required: true, message: '服务地址不能为空', trigger: 'blur' }]"
label="服务地址"
@ -37,29 +37,29 @@ onMounted(() => {
v-model:value="config.bootstrapServers"
placeholder="请输入服务地址localhost:9092"
/>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'username']"
:rules="[{ required: true, message: '用户名不能为空', trigger: 'blur' }]"
label="用户名"
>
<Input v-model:value="config.username" placeholder="请输入用户名" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'password']"
:rules="[{ required: true, message: '密码不能为空', trigger: 'blur' }]"
label="密码"
>
<Input.Password v-model:value="config.password" placeholder="请输入密码" />
</Form.Item>
<Form.Item :name="['config', 'ssl']" label="启用 SSL">
</FormItem>
<FormItem :name="['config', 'ssl']" label="启用 SSL">
<Switch v-model:checked="config.ssl" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'topic']"
:rules="[{ required: true, message: '主题不能为空', trigger: 'blur' }]"
label="主题"
>
<Input v-model:value="config.topic" placeholder="请输入主题" />
</Form.Item>
</FormItem>
</template>

View File

@ -4,7 +4,7 @@ import { onMounted } from 'vue';
import { isEmpty } from '@vben/utils';
import { useVModel } from '@vueuse/core';
import { Form, Input } from 'antdv-next';
import { FormItem, Input } from 'antdv-next';
import { IotDataSinkTypeEnum } from '#/api/iot/rule/data/sink';
@ -28,7 +28,7 @@ onMounted(() => {
</script>
<template>
<Form.Item
<FormItem
:name="['config', 'url']"
:rules="[{ required: true, message: '服务地址不能为空', trigger: 'blur' }]"
label="服务地址"
@ -37,22 +37,22 @@ onMounted(() => {
v-model:value="config.url"
placeholder="请输入 MQTT 服务地址mqtt://localhost:1883"
/>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'username']"
:rules="[{ required: true, message: '用户名不能为空', trigger: 'blur' }]"
label="用户名"
>
<Input v-model:value="config.username" placeholder="请输入用户名" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'password']"
:rules="[{ required: true, message: '密码不能为空', trigger: 'blur' }]"
label="密码"
>
<Input.Password v-model:value="config.password" placeholder="请输入密码" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'clientId']"
:rules="[
{ required: true, message: '客户端 ID 不能为空', trigger: 'blur' },
@ -60,12 +60,12 @@ onMounted(() => {
label="客户端 ID"
>
<Input v-model:value="config.clientId" placeholder="请输入客户端 ID" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'topic']"
:rules="[{ required: true, message: '主题不能为空', trigger: 'blur' }]"
label="主题"
>
<Input v-model:value="config.topic" placeholder="请输入主题" />
</Form.Item>
</FormItem>
</template>

View File

@ -4,7 +4,7 @@ import { onMounted } from 'vue';
import { isEmpty } from '@vben/utils';
import { useVModel } from '@vueuse/core';
import { Form, Input, InputNumber } from 'antdv-next';
import { FormItem, Input, InputNumber } from 'antdv-next';
import { IotDataSinkTypeEnum } from '#/api/iot/rule/data/sink';
@ -31,7 +31,7 @@ onMounted(() => {
</script>
<template>
<Form.Item
<FormItem
:name="['config', 'host']"
:rules="[{ required: true, message: '主机地址不能为空', trigger: 'blur' }]"
label="主机地址"
@ -40,8 +40,8 @@ onMounted(() => {
v-model:value="config.host"
placeholder="请输入主机地址localhost"
/>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'port']"
:rules="[
{ required: true, message: '端口不能为空', trigger: 'blur' },
@ -62,47 +62,47 @@ onMounted(() => {
placeholder="请输入端口"
class="w-full"
/>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'virtualHost']"
:rules="[{ required: true, message: '虚拟主机不能为空', trigger: 'blur' }]"
label="虚拟主机"
>
<Input v-model:value="config.virtualHost" placeholder="请输入虚拟主机" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'username']"
:rules="[{ required: true, message: '用户名不能为空', trigger: 'blur' }]"
label="用户名"
>
<Input v-model:value="config.username" placeholder="请输入用户名" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'password']"
:rules="[{ required: true, message: '密码不能为空', trigger: 'blur' }]"
label="密码"
>
<Input.Password v-model:value="config.password" placeholder="请输入密码" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'exchange']"
:rules="[{ required: true, message: '交换机不能为空', trigger: 'blur' }]"
label="交换机"
>
<Input v-model:value="config.exchange" placeholder="请输入交换机" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'routingKey']"
:rules="[{ required: true, message: '路由键不能为空', trigger: 'blur' }]"
label="路由键"
>
<Input v-model:value="config.routingKey" placeholder="请输入路由键" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'queue']"
:rules="[{ required: true, message: '队列不能为空', trigger: 'blur' }]"
label="队列"
>
<Input v-model:value="config.queue" placeholder="请输入队列" />
</Form.Item>
</FormItem>
</template>

View File

@ -4,7 +4,7 @@ import { onMounted } from 'vue';
import { isEmpty } from '@vben/utils';
import { useVModel } from '@vueuse/core';
import { Form, Input, InputNumber } from 'antdv-next';
import { FormItem, Input, InputNumber } from 'antdv-next';
import { IotDataSinkTypeEnum } from '#/api/iot/rule/data/sink';
@ -36,7 +36,7 @@ onMounted(() => {
</script>
<template>
<Form.Item
<FormItem
:name="['config', 'host']"
:rules="[{ required: true, message: '主机地址不能为空', trigger: 'blur' }]"
label="主机地址"
@ -45,8 +45,8 @@ onMounted(() => {
v-model:value="config.host"
placeholder="请输入主机地址localhost"
/>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'port']"
:rules="[
{ required: true, message: '端口不能为空', trigger: 'blur' },
@ -67,15 +67,15 @@ onMounted(() => {
placeholder="请输入端口"
class="w-full"
/>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'password']"
:rules="[{ required: true, message: '密码不能为空', trigger: 'blur' }]"
label="密码"
>
<Input.Password v-model:value="config.password" placeholder="请输入密码" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'database']"
:rules="[
{ required: true, message: '数据库索引不能为空', trigger: 'blur' },
@ -95,12 +95,12 @@ onMounted(() => {
placeholder="请输入数据库索引"
class="w-full"
/>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'topic']"
:rules="[{ required: true, message: '主题不能为空', trigger: 'blur' }]"
label="主题"
>
<Input v-model:value="config.topic" placeholder="请输入主题" />
</Form.Item>
</FormItem>
</template>

View File

@ -4,7 +4,7 @@ import { onMounted } from 'vue';
import { isEmpty } from '@vben/utils';
import { useVModel } from '@vueuse/core';
import { Form, Input } from 'antdv-next';
import { FormItem, Input } from 'antdv-next';
import { IotDataSinkTypeEnum } from '#/api/iot/rule/data/sink';
@ -29,7 +29,7 @@ onMounted(() => {
</script>
<template>
<Form.Item
<FormItem
:name="['config', 'nameServer']"
:rules="[
{ required: true, message: 'NameServer 地址不能为空', trigger: 'blur' },
@ -40,8 +40,8 @@ onMounted(() => {
v-model:value="config.nameServer"
placeholder="请输入 NameServer 地址127.0.0.1:9876"
/>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'accessKey']"
:rules="[
{ required: true, message: 'AccessKey 不能为空', trigger: 'blur' },
@ -49,8 +49,8 @@ onMounted(() => {
label="AccessKey"
>
<Input v-model:value="config.accessKey" placeholder="请输入 AccessKey" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'secretKey']"
:rules="[
{ required: true, message: 'SecretKey 不能为空', trigger: 'blur' },
@ -61,22 +61,22 @@ onMounted(() => {
v-model:value="config.secretKey"
placeholder="请输入 SecretKey"
/>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'group']"
:rules="[{ required: true, message: '消费组不能为空', trigger: 'blur' }]"
label="消费组"
>
<Input v-model:value="config.group" placeholder="请输入消费组" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'topic']"
:rules="[{ required: true, message: '主题不能为空', trigger: 'blur' }]"
label="主题"
>
<Input v-model:value="config.topic" placeholder="请输入主题" />
</Form.Item>
<Form.Item :name="['config', 'tags']" label="标签">
</FormItem>
<FormItem :name="['config', 'tags']" label="标签">
<Input v-model:value="config.tags" placeholder="请输入标签" />
</Form.Item>
</FormItem>
</template>

View File

@ -4,7 +4,7 @@ import { onMounted } from 'vue';
import { isEmpty } from '@vben/utils';
import { useVModel } from '@vueuse/core';
import { Form, Input, InputNumber, Select, Switch } from 'antdv-next';
import { FormItem, Input, InputNumber, Select, Switch } from 'antdv-next';
import { IotDataSinkTypeEnum } from '#/api/iot/rule/data/sink';
@ -33,7 +33,7 @@ onMounted(() => {
</script>
<template>
<Form.Item
<FormItem
:name="['config', 'host']"
:rules="[{ required: true, message: '主机地址不能为空', trigger: 'blur' }]"
label="服务器地址"
@ -42,8 +42,8 @@ onMounted(() => {
v-model:value="config.host"
placeholder="请输入 TCP 服务器地址localhost"
/>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'port']"
:rules="[
{ required: true, message: '端口不能为空', trigger: 'blur' },
@ -64,8 +64,8 @@ onMounted(() => {
placeholder="请输入端口"
class="w-full"
/>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'connectTimeoutMs']"
:rules="[
{ required: true, message: '连接超时时间不能为空', trigger: 'blur' },
@ -78,8 +78,8 @@ onMounted(() => {
:step="1000"
class="w-full"
/>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'readTimeoutMs']"
:rules="[
{ required: true, message: '读取超时时间不能为空', trigger: 'blur' },
@ -92,11 +92,11 @@ onMounted(() => {
:step="1000"
class="w-full"
/>
</Form.Item>
<Form.Item :name="['config', 'ssl']" label="启用 SSL">
</FormItem>
<FormItem :name="['config', 'ssl']" label="启用 SSL">
<Switch v-model:checked="config.ssl" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
v-if="config.ssl"
:name="['config', 'sslCertPath']"
label="SSL 证书路径"
@ -105,8 +105,8 @@ onMounted(() => {
v-model:value="config.sslCertPath"
placeholder="请输入 SSL 证书路径"
/>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'dataFormat']"
:rules="[
{ required: true, message: '数据格式不能为空', trigger: 'change' },
@ -117,8 +117,8 @@ onMounted(() => {
<Select.Option value="JSON">JSON</Select.Option>
<Select.Option value="BINARY">BINARY</Select.Option>
</Select>
</Form.Item>
<Form.Item :name="['config', 'heartbeatIntervalMs']" label="心跳间隔(ms)">
</FormItem>
<FormItem :name="['config', 'heartbeatIntervalMs']" label="心跳间隔(ms)">
<InputNumber
v-model:value="config.heartbeatIntervalMs"
:min="0"
@ -126,20 +126,20 @@ onMounted(() => {
placeholder="0 表示不启用心跳"
class="w-full"
/>
</Form.Item>
<Form.Item :name="['config', 'reconnectIntervalMs']" label="重连间隔(ms)">
</FormItem>
<FormItem :name="['config', 'reconnectIntervalMs']" label="重连间隔(ms)">
<InputNumber
v-model:value="config.reconnectIntervalMs"
:min="1000"
:step="1000"
class="w-full"
/>
</Form.Item>
<Form.Item :name="['config', 'maxReconnectAttempts']" label="最大重连次数">
</FormItem>
<FormItem :name="['config', 'maxReconnectAttempts']" label="最大重连次数">
<InputNumber
v-model:value="config.maxReconnectAttempts"
:min="0"
class="w-full"
/>
</Form.Item>
</FormItem>
</template>

View File

@ -4,7 +4,7 @@ import { onMounted } from 'vue';
import { isEmpty } from '@vben/utils';
import { useVModel } from '@vueuse/core';
import { Form, Input, InputNumber, Select, Switch } from 'antdv-next';
import { FormItem, Input, InputNumber, Select, Switch } from 'antdv-next';
import { IotDataSinkTypeEnum } from '#/api/iot/rule/data/sink';
@ -37,7 +37,7 @@ onMounted(() => {
</script>
<template>
<Form.Item
<FormItem
:name="['config', 'serverUrl']"
:rules="[
{
@ -52,8 +52,8 @@ onMounted(() => {
v-model:value="config.serverUrl"
placeholder="请输入 WebSocket 地址ws://localhost:8080/ws"
/>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'connectTimeoutMs']"
:rules="[
{ required: true, message: '连接超时时间不能为空', trigger: 'blur' },
@ -66,8 +66,8 @@ onMounted(() => {
:step="1000"
class="w-full"
/>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'sendTimeoutMs']"
:rules="[
{ required: true, message: '发送超时时间不能为空', trigger: 'blur' },
@ -80,8 +80,8 @@ onMounted(() => {
:step="1000"
class="w-full"
/>
</Form.Item>
<Form.Item :name="['config', 'heartbeatIntervalMs']" label="心跳间隔(ms)">
</FormItem>
<FormItem :name="['config', 'heartbeatIntervalMs']" label="心跳间隔(ms)">
<InputNumber
v-model:value="config.heartbeatIntervalMs"
:min="0"
@ -89,30 +89,30 @@ onMounted(() => {
placeholder="0 表示不启用心跳"
class="w-full"
/>
</Form.Item>
<Form.Item :name="['config', 'heartbeatMessage']" label="心跳消息">
</FormItem>
<FormItem :name="['config', 'heartbeatMessage']" label="心跳消息">
<Input
v-model:value="config.heartbeatMessage"
placeholder="请输入心跳消息内容JSON 格式)"
/>
</Form.Item>
<Form.Item :name="['config', 'subprotocols']" label="子协议">
</FormItem>
<FormItem :name="['config', 'subprotocols']" label="子协议">
<Input
v-model:value="config.subprotocols"
placeholder="请输入子协议列表,多个用逗号分隔"
/>
</Form.Item>
<Form.Item :name="['config', 'customHeaders']" label="自定义请求头">
</FormItem>
<FormItem :name="['config', 'customHeaders']" label="自定义请求头">
<Input.TextArea
v-model:value="config.customHeaders"
placeholder="请输入自定义请求头JSON 格式)"
:rows="3"
/>
</Form.Item>
<Form.Item :name="['config', 'verifySslCert']" label="验证 SSL 证书">
</FormItem>
<FormItem :name="['config', 'verifySslCert']" label="验证 SSL 证书">
<Switch v-model:checked="config.verifySslCert" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['config', 'dataFormat']"
:rules="[
{ required: true, message: '数据格式不能为空', trigger: 'change' },
@ -123,38 +123,38 @@ onMounted(() => {
<Select.Option value="JSON">JSON</Select.Option>
<Select.Option value="TEXT">TEXT</Select.Option>
</Select>
</Form.Item>
<Form.Item :name="['config', 'reconnectIntervalMs']" label="重连间隔(ms)">
</FormItem>
<FormItem :name="['config', 'reconnectIntervalMs']" label="重连间隔(ms)">
<InputNumber
v-model:value="config.reconnectIntervalMs"
:min="1000"
:step="1000"
class="w-full"
/>
</Form.Item>
<Form.Item :name="['config', 'maxReconnectAttempts']" label="最大重连次数">
</FormItem>
<FormItem :name="['config', 'maxReconnectAttempts']" label="最大重连次数">
<InputNumber
v-model:value="config.maxReconnectAttempts"
:min="0"
class="w-full"
/>
</Form.Item>
<Form.Item :name="['config', 'enableCompression']" label="启用压缩">
</FormItem>
<FormItem :name="['config', 'enableCompression']" label="启用压缩">
<Switch v-model:checked="config.enableCompression" />
</Form.Item>
<Form.Item :name="['config', 'sendRetryCount']" label="发送重试次数">
</FormItem>
<FormItem :name="['config', 'sendRetryCount']" label="发送重试次数">
<InputNumber
v-model:value="config.sendRetryCount"
:min="0"
class="w-full"
/>
</Form.Item>
<Form.Item :name="['config', 'sendRetryIntervalMs']" label="重试间隔(ms)">
</FormItem>
<FormItem :name="['config', 'sendRetryIntervalMs']" label="重试间隔(ms)">
<InputNumber
v-model:value="config.sendRetryIntervalMs"
:min="100"
:step="500"
class="w-full"
/>
</Form.Item>
</FormItem>
</template>

View File

@ -7,7 +7,7 @@ import { useVbenModal } from '@vben/common-ui';
import { CommonStatusEnum, DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { Form, Input, message, Radio, Select } from 'antdv-next';
import { Form, FormItem, Input, message, Radio, Select } from 'antdv-next';
import {
createDataSink,
@ -102,7 +102,7 @@ function handleTypeChange(type: number) {
:wrapper-col="{ span: 18 }"
class="mx-4"
>
<Form.Item
<FormItem
:rules="[
{ required: true, message: '目的名称不能为空', trigger: 'blur' },
]"
@ -110,15 +110,15 @@ function handleTypeChange(type: number) {
name="name"
>
<Input v-model:value="formData.name" placeholder="请输入目的名称" />
</Form.Item>
<Form.Item label="目的描述" name="description">
</FormItem>
<FormItem label="目的描述" name="description">
<Input.TextArea
v-model:value="formData.description"
placeholder="请输入目的描述"
:rows="3"
/>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:rules="[
{ required: true, message: '目的类型不能为空', trigger: 'change' },
]"
@ -133,7 +133,7 @@ function handleTypeChange(type: number) {
placeholder="请选择目的类型"
@change="(value: any) => handleTypeChange(value as number)"
/>
</Form.Item>
</FormItem>
<!-- 配置项按目的类型分支 -->
<HttpConfigForm
v-if="formData.type === IotDataSinkTypeEnum.HTTP"
@ -171,7 +171,7 @@ function handleTypeChange(type: number) {
v-if="formData.type === IotDataSinkTypeEnum.REDIS_STREAM"
v-model="formData.config"
/>
<Form.Item
<FormItem
:rules="[
{ required: true, message: '目的状态不能为空', trigger: 'change' },
]"
@ -187,7 +187,7 @@ function handleTypeChange(type: number) {
{{ dict.label }}
</Radio>
</Radio.Group>
</Form.Item>
</FormItem>
</Form>
</Modal>
</template>

View File

@ -3,7 +3,7 @@
import { onMounted, ref } from 'vue';
import { useVModel } from '@vueuse/core';
import { Form, Select } from 'antdv-next';
import { FormItem, Select } from 'antdv-next';
import { getSimpleAlertConfigList } from '#/api/iot/alert/config';
@ -46,7 +46,7 @@ onMounted(() => {
<template>
<div class="w-full">
<Form.Item label="告警配置" required>
<FormItem label="告警配置" required>
<Select
v-model:value="localValue"
placeholder="请选择告警配置"
@ -63,6 +63,6 @@ onMounted(() => {
:value="config.id"
/>
</Select>
</Form.Item>
</FormItem>
</div>
</template>

View File

@ -12,7 +12,7 @@ import {
} from '@vben/constants';
import { useVModel } from '@vueuse/core';
import { Col, Form, Row, Select } from 'antdv-next';
import { Col, FormItem, Row, Select } from 'antdv-next';
import ValueInput from '../inputs/value-input.vue';
import DeviceSelector from '../selectors/device-selector.vue';
@ -160,7 +160,7 @@ function handleOperatorChange() {
<!-- 条件类型选择 -->
<Row :gutter="16">
<Col :span="8">
<Form.Item label="条件类型" required>
<FormItem label="条件类型" required>
<Select
:value="condition.type"
@change="
@ -180,14 +180,14 @@ function handleOperatorChange() {
{{ option.label }}
</Select.Option>
</Select>
</Form.Item>
</FormItem>
</Col>
</Row>
<!-- 产品设备选择 - 设备相关条件的公共部分 -->
<Row v-if="isDeviceCondition" :gutter="16">
<Col :span="12">
<Form.Item label="产品" required>
<FormItem label="产品" required>
<ProductSelector
:model-value="condition.productId"
@update:model-value="
@ -195,10 +195,10 @@ function handleOperatorChange() {
"
@change="handleProductChange"
/>
</Form.Item>
</FormItem>
</Col>
<Col :span="12">
<Form.Item label="设备" required>
<FormItem label="设备" required>
<DeviceSelector
:model-value="condition.deviceId"
@update:model-value="
@ -207,7 +207,7 @@ function handleOperatorChange() {
:product-id="condition.productId"
@change="handleDeviceChange"
/>
</Form.Item>
</FormItem>
</Col>
</Row>
@ -222,7 +222,7 @@ function handleOperatorChange() {
<Row :gutter="16">
<!-- 操作符选择 -->
<Col :span="12">
<Form.Item label="操作符" required>
<FormItem label="操作符" required>
<Select
:value="condition.operator"
@change="(value: any) => updateConditionField('operator', value)"
@ -237,12 +237,12 @@ function handleOperatorChange() {
{{ option.label }}
</Select.Option>
</Select>
</Form.Item>
</FormItem>
</Col>
<!-- 状态选择 -->
<Col :span="12">
<Form.Item label="设备状态" required>
<FormItem label="设备状态" required>
<Select
:value="condition.param"
@change="(value: any) => updateConditionField('param', value)"
@ -257,7 +257,7 @@ function handleOperatorChange() {
{{ option.label }}
</Select.Option>
</Select>
</Form.Item>
</FormItem>
</Col>
</Row>
</div>
@ -273,7 +273,7 @@ function handleOperatorChange() {
<Row :gutter="16">
<!-- 属性/事件/服务选择 -->
<Col :span="6">
<Form.Item label="监控项" required>
<FormItem label="监控项" required>
<PropertySelector
:model-value="condition.identifier"
@update:model-value="
@ -284,12 +284,12 @@ function handleOperatorChange() {
:device-id="condition.deviceId"
@change="handlePropertyChange"
/>
</Form.Item>
</FormItem>
</Col>
<!-- 操作符选择 -->
<Col :span="6">
<Form.Item label="操作符" required>
<FormItem label="操作符" required>
<OperatorSelector
:model-value="condition.operator"
@update:model-value="
@ -298,12 +298,12 @@ function handleOperatorChange() {
:property-type="propertyType"
@change="handleOperatorChange"
/>
</Form.Item>
</FormItem>
</Col>
<!-- 值输入 -->
<Col :span="12">
<Form.Item label="比较值" required>
<FormItem label="比较值" required>
<ValueInput
:model-value="condition.param"
@update:model-value="
@ -313,7 +313,7 @@ function handleOperatorChange() {
:operator="condition.operator"
:property-config="propertyConfig"
/>
</Form.Item>
</FormItem>
</Col>
</Row>
</div>

View File

@ -14,7 +14,7 @@ import { useVModel } from '@vueuse/core';
import {
Col,
DatePicker,
Form,
FormItem,
Row,
Select,
Tag,
@ -178,7 +178,7 @@ watch(
<Row :gutter="16">
<!-- 时间操作符选择 -->
<Col :span="8">
<Form.Item label="时间条件" required>
<FormItem label="时间条件" required>
<Select
:value="condition.operator"
@update:value="
@ -204,12 +204,12 @@ watch(
</div>
</Select.Option>
</Select>
</Form.Item>
</FormItem>
</Col>
<!-- 时间值输入 -->
<Col :span="8">
<Form.Item label="时间值" required>
<FormItem label="时间值" required>
<TimePicker
v-if="needsTimeInput"
:value="timeValue"
@ -230,12 +230,12 @@ watch(
class="w-full"
/>
<div v-else class="text-sm text-muted-foreground">无需设置时间值</div>
</Form.Item>
</FormItem>
</Col>
<!-- 第二个时间值范围条件 -->
<Col :span="8" v-if="needsSecondTimeInput">
<Form.Item label="结束时间" required>
<FormItem label="结束时间" required>
<TimePicker
v-if="needsTimeInput"
:value="timeValue2"
@ -255,7 +255,7 @@ watch(
value-format="YYYY-MM-DD HH:mm:ss"
class="w-full"
/>
</Form.Item>
</FormItem>
</Col>
</Row>
</div>

View File

@ -13,7 +13,7 @@ import {
import { isObject } from '@vben/utils';
import { useVModel } from '@vueuse/core';
import { Col, Form, Row, Select, Tag } from 'antdv-next';
import { Col, FormItem, Row, Select, Tag } from 'antdv-next';
import { getThingModelTSLByProductId } from '#/api/iot/thingmodel';
@ -315,21 +315,21 @@ watch(
<!-- 产品和设备选择 - 与触发器保持一致的分离式选择器 -->
<Row :gutter="16">
<Col :span="12">
<Form.Item label="产品" required>
<FormItem label="产品" required>
<ProductSelector
v-model="action.productId"
@change="handleProductChange"
/>
</Form.Item>
</FormItem>
</Col>
<Col :span="12">
<Form.Item label="设备" required>
<FormItem label="设备" required>
<DeviceSelector
v-model="action.deviceId"
:product-id="action.productId"
@change="handleDeviceChange"
/>
</Form.Item>
</FormItem>
</Col>
</Row>
@ -338,7 +338,7 @@ watch(
v-if="action.productId && isServiceInvokeAction"
class="space-y-[16px]"
>
<Form.Item label="服务" required>
<FormItem label="服务" required>
<Select
v-model:value="action.identifier"
placeholder="请选择服务"
@ -364,32 +364,32 @@ watch(
</div>
</Select.Option>
</Select>
</Form.Item>
</FormItem>
<!-- 服务参数配置 -->
<div v-if="action.identifier" class="space-y-[16px]">
<Form.Item label="服务参数" required>
<FormItem label="服务参数" required>
<JsonParamsInput
v-model="paramsValue"
type="service"
:config="{ service: selectedService } as any"
placeholder="请输入 JSON 格式的服务参数"
/>
</Form.Item>
</FormItem>
</div>
</div>
<!-- 控制参数配置 - 属性设置类型时显示 -->
<div v-if="action.productId && isPropertySetAction" class="space-y-[16px]">
<!-- 参数配置 -->
<Form.Item label="参数" required>
<FormItem label="参数" required>
<JsonParamsInput
v-model="paramsValue"
type="property"
:config="{ properties: thingModelProperties }"
placeholder="请输入 JSON 格式的控制参数"
/>
</Form.Item>
</FormItem>
</div>
</div>
</template>

View File

@ -12,7 +12,7 @@ import {
} from '@vben/constants';
import { useVModel } from '@vueuse/core';
import { Col, Form, Input, Row, Select } from 'antdv-next';
import { Col, FormItem, Input, Row, Select } from 'antdv-next';
import JsonParamsInput from '../inputs/json-params-input.vue';
import ValueInput from '../inputs/value-input.vue';
@ -168,7 +168,7 @@ function handlePropertyChange(propertyInfo: any) {
<template>
<div class="space-y-4">
<!-- 触发事件类型选择 -->
<Form.Item label="触发事件类型" required>
<FormItem label="触发事件类型" required>
<Select
:value="triggerType"
@change="(value: any) => handleTriggerTypeChange(value)"
@ -183,14 +183,14 @@ function handlePropertyChange(propertyInfo: any) {
{{ option.label }}
</Select.Option>
</Select>
</Form.Item>
</FormItem>
<!-- 设备属性条件配置 -->
<div v-if="isDevicePropertyTrigger" class="space-y-4">
<!-- 产品设备选择 -->
<Row :gutter="16">
<Col :span="12">
<Form.Item label="产品" required>
<FormItem label="产品" required>
<ProductSelector
:model-value="condition.productId"
@update:model-value="
@ -198,10 +198,10 @@ function handlePropertyChange(propertyInfo: any) {
"
@change="handleProductChange"
/>
</Form.Item>
</FormItem>
</Col>
<Col :span="12">
<Form.Item label="设备" required>
<FormItem label="设备" required>
<DeviceSelector
:model-value="condition.deviceId"
@update:model-value="
@ -210,7 +210,7 @@ function handlePropertyChange(propertyInfo: any) {
:product-id="condition.productId"
@change="handleDeviceChange"
/>
</Form.Item>
</FormItem>
</Col>
</Row>
@ -218,7 +218,7 @@ function handlePropertyChange(propertyInfo: any) {
<Row :gutter="16">
<!-- 属性/事件/服务选择 -->
<Col :span="6">
<Form.Item label="监控项" required>
<FormItem label="监控项" required>
<PropertySelector
:model-value="condition.identifier"
@update:model-value="
@ -229,12 +229,12 @@ function handlePropertyChange(propertyInfo: any) {
:device-id="condition.deviceId"
@change="handlePropertyChange"
/>
</Form.Item>
</FormItem>
</Col>
<!-- 操作符选择 - 服务调用和事件上报不需要操作符 -->
<Col v-if="needsOperatorSelector" :span="6">
<Form.Item label="操作符" required>
<FormItem label="操作符" required>
<OperatorSelector
:model-value="condition.operator"
@update:model-value="
@ -242,12 +242,12 @@ function handlePropertyChange(propertyInfo: any) {
"
:property-type="propertyType"
/>
</Form.Item>
</FormItem>
</Col>
<!-- 值输入 -->
<Col :span="isWideValueColumn ? 18 : 12">
<Form.Item :label="valueInputLabel" required>
<FormItem :label="valueInputLabel" required>
<!-- 服务调用参数配置 -->
<JsonParamsInput
v-if="
@ -265,9 +265,7 @@ function handlePropertyChange(propertyInfo: any) {
triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST
"
:value="condition.value"
@update:value="
(value) => updateConditionField('value', value)
"
@update:value="(value) => updateConditionField('value', value)"
placeholder="留空则事件发生即匹配"
/>
<!-- 普通值输入 -->
@ -281,7 +279,7 @@ function handlePropertyChange(propertyInfo: any) {
:operator="condition.operator"
:property-config="propertyConfig"
/>
</Form.Item>
</FormItem>
</Col>
</Row>
</div>
@ -291,7 +289,7 @@ function handlePropertyChange(propertyInfo: any) {
<!-- 设备状态触发器使用简化的配置 -->
<Row :gutter="16">
<Col :span="12">
<Form.Item label="产品" required>
<FormItem label="产品" required>
<ProductSelector
:model-value="condition.productId"
@update:model-value="
@ -299,10 +297,10 @@ function handlePropertyChange(propertyInfo: any) {
"
@change="handleProductChange"
/>
</Form.Item>
</FormItem>
</Col>
<Col :span="12">
<Form.Item label="设备" required>
<FormItem label="设备" required>
<DeviceSelector
:model-value="condition.deviceId"
@update:model-value="
@ -311,12 +309,12 @@ function handlePropertyChange(propertyInfo: any) {
:product-id="condition.productId"
@change="handleDeviceChange"
/>
</Form.Item>
</FormItem>
</Col>
</Row>
<Row :gutter="16">
<Col :span="6">
<Form.Item label="操作符" required>
<FormItem label="操作符" required>
<Select
:value="condition.operator"
@change="(value: any) => updateConditionField('operator', value)"
@ -333,10 +331,10 @@ function handlePropertyChange(propertyInfo: any) {
}}
</Select.Option>
</Select>
</Form.Item>
</FormItem>
</Col>
<Col :span="6">
<Form.Item label="参数" required>
<FormItem label="参数" required>
<Select
:value="condition.value"
@change="(value: any) => updateConditionField('value', value)"
@ -351,7 +349,7 @@ function handlePropertyChange(propertyInfo: any) {
{{ option.label }}
</Select.Option>
</Select>
</Form.Item>
</FormItem>
</Col>
</Row>
</div>

View File

@ -11,7 +11,7 @@ import { IconifyIcon } from '@vben/icons';
import { getStableObjectKey } from '@vben/utils';
import { useVModel } from '@vueuse/core';
import { Button, Card, Empty, Form, Select, Tag } from 'antdv-next';
import { Button, Card, Empty, FormItem, Select, Tag } from 'antdv-next';
import AlertConfig from '../configs/alert-config.vue';
import DeviceControlConfig from '../configs/device-control-config.vue';
@ -228,7 +228,7 @@ function onActionTypeChange(action: RuleSceneApi.Action, type: number) {
<div class="p-[16px] space-y-[16px]">
<!-- 执行类型选择 -->
<div class="w-full">
<Form.Item label="执行类型" required>
<FormItem label="执行类型" required>
<Select
:value="action.type"
@change="(value) => updateActionType(index, value as number)"
@ -243,7 +243,7 @@ function onActionTypeChange(action: RuleSceneApi.Action, type: number) {
{{ option.label }}
</Select.Option>
</Select>
</Form.Item>
</FormItem>
</div>
<!-- 设备控制配置 -->

View File

@ -7,7 +7,7 @@ import { getDictOptions } from '@vben/hooks';
import { IconifyIcon } from '@vben/icons';
import { useVModel } from '@vueuse/core';
import { Card, Col, Form, Input, Radio, Row } from 'antdv-next';
import { Card, Col, FormItem, Input, Radio, Row } from 'antdv-next';
import { DictTag } from '#/components/dict-tag';
@ -44,7 +44,7 @@ const formData = useVModel(props, 'modelValue', emit); // 表单数据
<div class="p-0">
<Row :gutter="24" class="mb-[24px]">
<Col :span="12">
<Form.Item label="场景名称" name="name" required>
<FormItem label="场景名称" name="name" required>
<Input
v-model:value="formData.name"
placeholder="请输入场景名称"
@ -52,10 +52,10 @@ const formData = useVModel(props, 'modelValue', emit); // 表单数据
show-word-limit
allow-clear
/>
</Form.Item>
</FormItem>
</Col>
<Col :span="12">
<Form.Item label="场景状态" name="status" required>
<FormItem label="场景状态" name="status" required>
<Radio.Group v-model:value="formData.status">
<Radio
v-for="(dict, index) in getDictOptions(
@ -68,10 +68,10 @@ const formData = useVModel(props, 'modelValue', emit); // 表单数据
{{ dict.label }}
</Radio>
</Radio.Group>
</Form.Item>
</FormItem>
</Col>
</Row>
<Form.Item label="场景描述" name="description">
<FormItem label="场景描述" name="description">
<Input.TextArea
v-model:value="formData.description"
placeholder="请输入场景描述(可选)"
@ -80,7 +80,7 @@ const formData = useVModel(props, 'modelValue', emit); // 表单数据
show-word-limit
resize="none"
/>
</Form.Item>
</FormItem>
</div>
</Card>
</template>

View File

@ -12,7 +12,7 @@ import { IconifyIcon } from '@vben/icons';
import { getStableObjectKey } from '@vben/utils';
import { useVModel } from '@vueuse/core';
import { Button, Card, Empty, Form, Tag } from 'antdv-next';
import { Button, Card, Empty, FormItem, Tag } from 'antdv-next';
import { CronTab } from '#/components/cron-tab';
@ -208,14 +208,14 @@ onMounted(() => {
<div
class="p-[16px] rounded-[6px] border border-primary bg-background"
>
<Form.Item label="CRON 表达式" required>
<FormItem label="CRON 表达式" required>
<CronTab
:model-value="triggerItem.cronExpression || '0 0 12 * * ?'"
@update:model-value="
(value) => updateTriggerCronConfig(index, value)
"
/>
</Form.Item>
</FormItem>
</div>
<!-- 附加条件组配置 -->

View File

@ -5,7 +5,7 @@ import type { Ref } from 'vue';
import { getDataTypeOptions, IoTDataSpecsDataTypeEnum } from '@vben/constants';
import { useVModel } from '@vueuse/core';
import { Form, Input, Radio } from 'antdv-next';
import { FormItem, Input, Radio } from 'antdv-next';
import { ThingModelFormRules } from '#/api/iot/thingmodel';
@ -34,7 +34,7 @@ function handleChange(e: any) {
</script>
<template>
<Form.Item
<FormItem
:name="['property', 'dataSpecs', 'childDataType']"
:rules="ThingModelFormRules.childDataType"
label="元素类型"
@ -49,8 +49,8 @@ function handleChange(e: any) {
{{ `${item.value}(${item.label})` }}
</Radio>
</Radio.Group>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['property', 'dataSpecs', 'size']"
:rules="ThingModelFormRules.size"
label="元素个数"
@ -59,7 +59,7 @@ function handleChange(e: any) {
v-model:value="dataSpecs.size"
placeholder="请输入数组中的元素个数"
/>
</Form.Item>
</FormItem>
<!-- Struct 型配置-->
<ThingModelStructDataSpecs
v-if="dataSpecs.childDataType === IoTDataSpecsDataTypeEnum.STRUCT"

View File

@ -6,7 +6,7 @@ import { IoTDataSpecsDataTypeEnum } from '@vben/constants';
import { isEmpty } from '@vben/utils';
import { useVModel } from '@vueuse/core';
import { Button, Form, Input, message } from 'antdv-next';
import { Button, FormItem, Input, message } from 'antdv-next';
import { buildIdentifierLikeNameValidator } from '#/api/iot/thingmodel';
@ -84,7 +84,7 @@ function validateEnumList(_rule: any, _value: any, callback: any) {
</script>
<template>
<Form.Item
<FormItem
:rules="[{ validator: validateEnumList, trigger: 'change' }]"
label="枚举项"
>
@ -98,7 +98,7 @@ function validateEnumList(_rule: any, _value: any, callback: any) {
:key="index"
class="mb-[5px] flex items-center justify-between"
>
<Form.Item
<FormItem
:name="['property', 'dataSpecsList', index, 'value']"
:rules="[
{ required: true, message: '枚举值不能为空', trigger: 'blur' },
@ -110,9 +110,9 @@ function validateEnumList(_rule: any, _value: any, callback: any) {
v-model:value="item.value"
placeholder="请输入枚举值如「0」"
/>
</Form.Item>
</FormItem>
<span class="mx-2">~</span>
<Form.Item
<FormItem
:name="['property', 'dataSpecsList', index, 'name']"
:rules="[
{ required: true, message: '枚举描述不能为空', trigger: 'blur' },
@ -121,14 +121,14 @@ function validateEnumList(_rule: any, _value: any, callback: any) {
class="mb-0 flex-1"
>
<Input v-model:value="item.name" placeholder="对该枚举项的描述" />
</Form.Item>
</FormItem>
<Button class="ml-2.5" type="link" @click="deleteEnum(index)">
删除
</Button>
</div>
<Button type="link" @click="addEnum">+ </Button>
</div>
</Form.Item>
</FormItem>
</template>
<style lang="scss" scoped>

View File

@ -10,7 +10,7 @@ import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { useVModel } from '@vueuse/core';
import { Form, Input, Select } from 'antdv-next';
import { FormItem, Input, Select } from 'antdv-next';
const props = defineProps<{ modelValue: any }>();
const emits = defineEmits(['update:modelValue']);
@ -87,9 +87,9 @@ function validateStep(_rule: any, _value: any, callback: any) {
</script>
<template>
<Form.Item label="取值范围">
<FormItem label="取值范围">
<div class="flex items-center justify-between">
<Form.Item
<FormItem
:name="['property', 'dataSpecs', 'min']"
:rules="[
{ required: true, message: '最小值不能为空', trigger: 'blur' },
@ -98,9 +98,9 @@ function validateStep(_rule: any, _value: any, callback: any) {
class="mb-0 flex-1"
>
<Input v-model:value="dataSpecs.min" placeholder="请输入最小值" />
</Form.Item>
</FormItem>
<span class="mx-2">~</span>
<Form.Item
<FormItem
:name="['property', 'dataSpecs', 'max']"
:rules="[
{ required: true, message: '最大值不能为空', trigger: 'blur' },
@ -109,10 +109,10 @@ function validateStep(_rule: any, _value: any, callback: any) {
class="mb-0 flex-1"
>
<Input v-model:value="dataSpecs.max" placeholder="请输入最大值" />
</Form.Item>
</FormItem>
</div>
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['property', 'dataSpecs', 'step']"
:rules="[
{ required: true, message: '步长不能为空', trigger: 'blur' },
@ -121,8 +121,8 @@ function validateStep(_rule: any, _value: any, callback: any) {
label="步长"
>
<Input v-model:value="dataSpecs.step" placeholder="请输入步长" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:name="['property', 'dataSpecs', 'unit']"
:rules="[{ required: true, message: '请选择单位', trigger: 'change' }]"
label="单位"
@ -142,7 +142,7 @@ function validateStep(_rule: any, _value: any, callback: any) {
{{ `${item.label}-${item.value}` }}
</Select.Option>
</Select>
</Form.Item>
</FormItem>
</template>
<style lang="scss" scoped>

View File

@ -8,7 +8,7 @@ import { IoTDataSpecsDataTypeEnum } from '@vben/constants';
import { cloneDeep, isEmpty } from '@vben/utils';
import { useVModel } from '@vueuse/core';
import { Button, Divider, Form, Input } from 'antdv-next';
import { Button, Divider, Form, FormItem, Input } from 'antdv-next';
import { ThingModelFormRules } from '#/api/iot/thingmodel';
@ -130,7 +130,7 @@ onMounted(() => {
</script>
<template>
<Form.Item
<FormItem
:name="fieldPath"
:rules="[{ validator: validateStructSpecsList, trigger: 'change' }]"
label="属性对象"
@ -150,7 +150,7 @@ onMounted(() => {
</div>
</div>
<Button type="link" @click="openStructForm(null)">+ </Button>
</Form.Item>
</FormItem>
<!-- 结构体参数表单 -->
<Modal class="w-2/5" title="结构体参数">
@ -161,16 +161,16 @@ onMounted(() => {
:wrapper-col="{ span: 18 }"
class="mx-4"
>
<Form.Item :rules="ThingModelFormRules.name" label="参数名称" name="name">
<FormItem :rules="ThingModelFormRules.name" label="参数名称" name="name">
<Input v-model:value="formData.name" placeholder="请输入参数名称" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:rules="ThingModelFormRules.identifier"
label="标识符"
name="identifier"
>
<Input v-model:value="formData.identifier" placeholder="请输入标识符" />
</Form.Item>
</FormItem>
<!-- 属性配置 -->
<ThingModelProperty v-model="formData.property" is-struct-data-specs />
</Form>

View File

@ -11,7 +11,7 @@ import {
import { isEmpty } from '@vben/utils';
import { useVModel } from '@vueuse/core';
import { Form, Radio } from 'antdv-next';
import { FormItem, Radio } from 'antdv-next';
import { ThingModelFormRules } from '#/api/iot/thingmodel';
@ -32,7 +32,7 @@ watch(
</script>
<template>
<Form.Item
<FormItem
:name="['event', 'type']"
:rules="ThingModelFormRules.eventType"
label="事件类型"
@ -46,13 +46,13 @@ watch(
{{ eventType.label }}
</Radio>
</Radio.Group>
</Form.Item>
<Form.Item label="输出参数">
</FormItem>
<FormItem label="输出参数">
<ThingModelInputOutputParam
v-model="thingModelEvent.outputParams"
:direction="IoTThingModelParamDirectionEnum.OUTPUT"
/>
</Form.Item>
</FormItem>
</template>
<style lang="scss" scoped>

View File

@ -17,7 +17,7 @@ import { getDictOptions } from '@vben/hooks';
import { $t } from '@vben/locales';
import { cloneDeep, isEmpty } from '@vben/utils';
import { Form, Input, message, Radio } from 'antdv-next';
import { Form, FormItem, Input, message, Radio } from 'antdv-next';
import {
createThingModel,
@ -197,7 +197,7 @@ function removeDataSpecs(val: any) {
:wrapper-col="{ span: 18 }"
class="mx-4"
>
<Form.Item :rules="ThingModelFormRules.type" label="功能类型" name="type">
<FormItem :rules="ThingModelFormRules.type" label="功能类型" name="type">
<Radio.Group v-model:value="formData.type">
<Radio.Button
v-for="dict in getDictOptions(DICT_TYPE.IOT_THING_MODEL_TYPE)"
@ -207,20 +207,17 @@ function removeDataSpecs(val: any) {
{{ dict.label }}
</Radio.Button>
</Radio.Group>
</Form.Item>
<Form.Item :rules="ThingModelFormRules.name" label="功能名称" name="name">
</FormItem>
<FormItem :rules="ThingModelFormRules.name" label="功能名称" name="name">
<Input v-model:value="formData.name" placeholder="请输入功能名称" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:rules="ThingModelFormRules.identifier"
label="标识符"
name="identifier"
>
<Input
v-model:value="formData.identifier"
placeholder="请输入标识符"
/>
</Form.Item>
<Input v-model:value="formData.identifier" placeholder="请输入标识符" />
</FormItem>
<!-- 属性配置 -->
<ThingModelProperty
v-if="formData.type === IoTThingModelTypeEnum.PROPERTY"
@ -236,14 +233,14 @@ function removeDataSpecs(val: any) {
v-if="formData.type === IoTThingModelTypeEnum.EVENT"
v-model="formData.event"
/>
<Form.Item label="描述" name="description">
<FormItem label="描述" name="description">
<Input.TextArea
v-model:value="formData.description"
:maxlength="200"
:rows="3"
placeholder="请输入物模型描述"
/>
</Form.Item>
</FormItem>
</Form>
</Modal>
</template>

View File

@ -8,7 +8,7 @@ import { IoTDataSpecsDataTypeEnum } from '@vben/constants';
import { cloneDeep, isEmpty } from '@vben/utils';
import { useVModel } from '@vueuse/core';
import { Button, Divider, Form, Input, message } from 'antdv-next';
import { Button, Divider, Form, FormItem, Input, message } from 'antdv-next';
import { ThingModelFormRules } from '#/api/iot/thingmodel';
@ -146,16 +146,16 @@ function deleteParamItem(index: number) {
:wrapper-col="{ span: 18 }"
class="mx-4"
>
<Form.Item :rules="ThingModelFormRules.name" label="参数名称" name="name">
<FormItem :rules="ThingModelFormRules.name" label="参数名称" name="name">
<Input v-model:value="formData.name" placeholder="请输入参数名称" />
</Form.Item>
<Form.Item
</FormItem>
<FormItem
:rules="ThingModelFormRules.identifier"
label="标识符"
name="identifier"
>
<Input v-model:value="formData.identifier" placeholder="请输入标识符" />
</Form.Item>
</FormItem>
<!-- 属性配置 -->
<ThingModelProperty v-model="formData.property" is-params />
</Form>

View File

@ -14,7 +14,7 @@ import {
import { isEmpty } from '@vben/utils';
import { useVModel } from '@vueuse/core';
import { Form, Input, Radio, Select } from 'antdv-next';
import { FormItem, Input, Radio, Select } from 'antdv-next';
import { ThingModelFormRules, validateBoolName } from '#/api/iot/thingmodel';
@ -102,7 +102,7 @@ if (!props.isStructDataSpecs && !props.isParams) {
</script>
<template>
<Form.Item
<FormItem
:name="['property', 'dataType']"
:rules="[{ required: true, message: '请选择数据类型', trigger: 'change' }]"
label="数据类型"
@ -121,7 +121,7 @@ if (!props.isStructDataSpecs && !props.isParams) {
{{ `${option.value}(${option.label})` }}
</Select.Option>
</Select>
</Form.Item>
</FormItem>
<!-- 数值型配置 -->
<ThingModelNumberDataSpecs
v-if="NUMERIC_TYPES.has(property.dataType || '')"
@ -133,7 +133,7 @@ if (!props.isStructDataSpecs && !props.isParams) {
v-model="property.dataSpecsList"
/>
<!-- 布尔型配置 -->
<Form.Item
<FormItem
v-if="property.dataType === IoTDataSpecsDataTypeEnum.BOOL"
label="布尔值"
>
@ -141,7 +141,7 @@ if (!props.isStructDataSpecs && !props.isParams) {
<div class="mb-[5px] flex w-full items-center justify-start">
<span>{{ item.value }}</span>
<span class="mx-2">-</span>
<Form.Item
<FormItem
:name="['property', 'dataSpecsList', index, 'name']"
:rules="[
{ required: true, message: '布尔描述不能为空', trigger: 'blur' },
@ -154,12 +154,12 @@ if (!props.isStructDataSpecs && !props.isParams) {
:placeholder="`如:${item.value === 0 ? '关' : '开'}`"
class="!w-[255px]"
/>
</Form.Item>
</FormItem>
</div>
</template>
</Form.Item>
</FormItem>
<!-- 文本型配置 -->
<Form.Item
<FormItem
v-if="property.dataType === IoTDataSpecsDataTypeEnum.TEXT"
:name="['property', 'dataSpecs', 'length']"
:rules="ThingModelFormRules.length"
@ -172,9 +172,9 @@ if (!props.isStructDataSpecs && !props.isParams) {
>
<template #addonAfter>字节</template>
</Input>
</Form.Item>
</FormItem>
<!-- 时间型配置 -->
<Form.Item
<FormItem
v-if="property.dataType === IoTDataSpecsDataTypeEnum.DATE"
label="时间格式"
name="date"
@ -184,7 +184,7 @@ if (!props.isStructDataSpecs && !props.isParams) {
disabled
placeholder="String 类型的 UTC 时间戳(毫秒)"
/>
</Form.Item>
</FormItem>
<!-- 数组型配置-->
<ThingModelArrayDataSpecs
v-if="property.dataType === IoTDataSpecsDataTypeEnum.ARRAY"
@ -195,7 +195,7 @@ if (!props.isStructDataSpecs && !props.isParams) {
v-if="property.dataType === IoTDataSpecsDataTypeEnum.STRUCT"
v-model="property.dataSpecsList"
/>
<Form.Item
<FormItem
v-if="!isStructDataSpecs && !isParams"
:name="['property', 'accessMode']"
:rules="ThingModelFormRules.accessMode"
@ -210,7 +210,7 @@ if (!props.isStructDataSpecs && !props.isParams) {
{{ accessMode.label }}
</Radio>
</Radio.Group>
</Form.Item>
</FormItem>
</template>
<style lang="scss" scoped>

View File

@ -11,7 +11,7 @@ import {
import { isEmpty } from '@vben/utils';
import { useVModel } from '@vueuse/core';
import { Form, Radio } from 'antdv-next';
import { FormItem, Radio } from 'antdv-next';
import { ThingModelFormRules } from '#/api/iot/thingmodel';
@ -43,7 +43,7 @@ function getParamIdentifiers(params?: any[]) {
</script>
<template>
<Form.Item
<FormItem
:name="['service', 'callType']"
:rules="ThingModelFormRules.callType"
label="调用方式"
@ -57,21 +57,21 @@ function getParamIdentifiers(params?: any[]) {
{{ callType.label }}
</Radio>
</Radio.Group>
</Form.Item>
<Form.Item label="输入参数">
</FormItem>
<FormItem label="输入参数">
<ThingModelInputOutputParam
v-model="service.inputParams"
:direction="IoTThingModelParamDirectionEnum.INPUT"
:existing-identifiers="getParamIdentifiers(service.outputParams)"
/>
</Form.Item>
<Form.Item label="输出参数">
</FormItem>
<FormItem label="输出参数">
<ThingModelInputOutputParam
v-model="service.outputParams"
:direction="IoTThingModelParamDirectionEnum.OUTPUT"
:existing-identifiers="getParamIdentifiers(service.inputParams)"
/>
</Form.Item>
</FormItem>
</template>
<style lang="scss" scoped>

View File

@ -8,7 +8,7 @@ import { nextTick, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { formatDateTime } from '@vben/utils';
import { Descriptions, Spin } from 'antdv-next';
import { Descriptions, DescriptionsItem, Spin } from 'antdv-next';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getItemReceipt } from '#/api/mes/wm/itemreceipt';
@ -123,36 +123,36 @@ const [Modal, modalApi] = useVbenModal({
>
<Spin :spinning="loading">
<Descriptions bordered size="small" :column="3">
<Descriptions.Item label="入库单编号">
<DescriptionsItem label="入库单编号">
{{ formatEmpty(receipt?.code) }}
</Descriptions.Item>
<Descriptions.Item label="入库单名称">
</DescriptionsItem>
<DescriptionsItem label="入库单名称">
{{ formatEmpty(receipt?.name) }}
</Descriptions.Item>
<Descriptions.Item label="入库日期">
</DescriptionsItem>
<DescriptionsItem label="入库日期">
{{ formatDate(receipt?.receiptDate) }}
</Descriptions.Item>
<Descriptions.Item label="到货通知单">
</DescriptionsItem>
<DescriptionsItem label="到货通知单">
{{ formatEmpty(receipt?.noticeCode) }}
</Descriptions.Item>
<Descriptions.Item label="供应商">
</DescriptionsItem>
<DescriptionsItem label="供应商">
{{ formatEmpty(receipt?.vendorName) }}
</Descriptions.Item>
<Descriptions.Item label="采购订单号">
</DescriptionsItem>
<DescriptionsItem label="采购订单号">
{{ formatEmpty(receipt?.purchaseOrderCode) }}
</Descriptions.Item>
<Descriptions.Item label="仓库">
</DescriptionsItem>
<DescriptionsItem label="仓库">
{{ formatEmpty(receipt?.warehouseName) }}
</Descriptions.Item>
<Descriptions.Item label="库区">
</DescriptionsItem>
<DescriptionsItem label="库区">
{{ formatEmpty(receipt?.locationName) }}
</Descriptions.Item>
<Descriptions.Item label="库位">
</DescriptionsItem>
<DescriptionsItem label="库位">
{{ formatEmpty(receipt?.areaName) }}
</Descriptions.Item>
<Descriptions.Item label="备注" :span="3">
</DescriptionsItem>
<DescriptionsItem label="备注" :span="3">
{{ formatEmpty(receipt?.remark) }}
</Descriptions.Item>
</DescriptionsItem>
</Descriptions>
<div class="mt-4">
<Grid table-title="" />

View File

@ -12,6 +12,7 @@ import { getDictOptions } from '@vben/hooks';
import {
Form as AForm,
Divider,
FormItem,
Input,
InputNumber,
message,
@ -97,7 +98,7 @@ const [Modal, modalApi] = useVbenModal({
item.valueType === MesQcResultValueType.INTEGER
) {
submit.value =
item.valueNumber == null ? undefined : String(item.valueNumber);
item.valueNumber === null ? undefined : String(item.valueNumber);
} else {
submit.value = item.value;
}
@ -148,7 +149,7 @@ const [Modal, modalApi] = useVbenModal({
valueNumber:
(item.valueType === MesQcResultValueType.FLOAT ||
item.valueType === MesQcResultValueType.INTEGER) &&
item.value != null
item.value !== null
? Number(item.value)
: undefined,
}));
@ -178,9 +179,7 @@ const [Modal, modalApi] = useVbenModal({
:key="item.indicatorId ?? index"
class="mb-2"
>
<AForm.Item
:label="`检测项${index + 1}${item.indicatorName ?? ''}`"
>
<FormItem :label="`检测项${index + 1}${item.indicatorName ?? ''}`">
<InputNumber
v-if="
item.valueType === MesQcResultValueType.FLOAT ||
@ -210,7 +209,7 @@ const [Modal, modalApi] = useVbenModal({
placeholder="请输入文件地址"
/>
<Input v-else v-model:value="item.value" placeholder="请输入" />
</AForm.Item>
</FormItem>
</div>
</AForm>
</div>

View File

@ -8,7 +8,7 @@ import { computed, ref } from 'vue';
import { confirm, useVbenModal } from '@vben/common-ui';
import { MesQcStatusEnum, MesQcTypeEnum } from '@vben/constants';
import { Button, Descriptions, message, Tabs } from 'antdv-next';
import { Button, Descriptions, DescriptionsItem, message, Tabs } from 'antdv-next';
import { useVbenForm } from '#/adapter/form';
import {
@ -188,24 +188,24 @@ const [Modal, modalApi] = useVbenModal({
<!-- 缺陷统计只读 -->
<div v-if="formData?.id" class="mx-4 mt-4">
<Descriptions title="缺陷情况" :column="3" bordered size="small">
<Descriptions.Item label="致命缺陷数">
<DescriptionsItem label="致命缺陷数">
{{ formData.criticalQuantity ?? 0 }}
</Descriptions.Item>
<Descriptions.Item label="严重缺陷数">
</DescriptionsItem>
<DescriptionsItem label="严重缺陷数">
{{ formData.majorQuantity ?? 0 }}
</Descriptions.Item>
<Descriptions.Item label="轻微缺陷数">
</DescriptionsItem>
<DescriptionsItem label="轻微缺陷数">
{{ formData.minorQuantity ?? 0 }}
</Descriptions.Item>
<Descriptions.Item label="致命缺陷率">
</DescriptionsItem>
<DescriptionsItem label="致命缺陷率">
{{ formData.criticalRate ?? 0 }}%
</Descriptions.Item>
<Descriptions.Item label="严重缺陷率">
</DescriptionsItem>
<DescriptionsItem label="严重缺陷率">
{{ formData.majorRate ?? 0 }}%
</Descriptions.Item>
<Descriptions.Item label="轻微缺陷率">
</DescriptionsItem>
<DescriptionsItem label="轻微缺陷率">
{{ formData.minorRate ?? 0 }}%
</Descriptions.Item>
</DescriptionsItem>
</Descriptions>
</div>
<Tabs

View File

@ -11,17 +11,13 @@ import { MesQcStatusEnum, MesQcTypeEnum } from '@vben/constants';
import {
Button,
Descriptions,
DescriptionsItem,
message,
Tabs,
} from 'antdv-next';
import { useVbenForm } from '#/adapter/form';
import {
createIqc,
finishIqc,
getIqc,
updateIqc,
} from '#/api/mes/qc/iqc';
import { createIqc, finishIqc, getIqc, updateIqc } from '#/api/mes/qc/iqc';
import { $t } from '#/locales';
import { QcIndicatorResultList } from '../../indicatorresult/components';
@ -194,24 +190,24 @@ const [Modal, modalApi] = useVbenModal({
<!-- 缺陷统计只读 -->
<div v-if="formData?.id" class="mx-4 mt-4">
<Descriptions title="缺陷情况" :column="3" bordered size="small">
<Descriptions.Item label="致命缺陷数">
<DescriptionsItem label="致命缺陷数">
{{ formData.criticalQuantity ?? 0 }}
</Descriptions.Item>
<Descriptions.Item label="严重缺陷数">
</DescriptionsItem>
<DescriptionsItem label="严重缺陷数">
{{ formData.majorQuantity ?? 0 }}
</Descriptions.Item>
<Descriptions.Item label="轻微缺陷数">
</DescriptionsItem>
<DescriptionsItem label="轻微缺陷数">
{{ formData.minorQuantity ?? 0 }}
</Descriptions.Item>
<Descriptions.Item label="致命缺陷率">
</DescriptionsItem>
<DescriptionsItem label="致命缺陷率">
{{ formData.criticalRate ?? 0 }}%
</Descriptions.Item>
<Descriptions.Item label="严重缺陷率">
</DescriptionsItem>
<DescriptionsItem label="严重缺陷率">
{{ formData.majorRate ?? 0 }}%
</Descriptions.Item>
<Descriptions.Item label="轻微缺陷率">
</DescriptionsItem>
<DescriptionsItem label="轻微缺陷率">
{{ formData.minorRate ?? 0 }}%
</Descriptions.Item>
</DescriptionsItem>
</Descriptions>
</div>
<Tabs

View File

@ -8,7 +8,7 @@ import { computed, ref } from 'vue';
import { confirm, useVbenModal } from '@vben/common-ui';
import { MesQcStatusEnum, MesQcTypeEnum } from '@vben/constants';
import { Button, Descriptions, message, Tabs } from 'antdv-next';
import { Button, Descriptions, DescriptionsItem, message, Tabs } from 'antdv-next';
import { useVbenForm } from '#/adapter/form';
import {
@ -192,24 +192,24 @@ const [Modal, modalApi] = useVbenModal({
<!-- 缺陷统计只读 -->
<div v-if="formData?.id" class="mx-4 mt-4">
<Descriptions title="缺陷情况" :column="3" bordered size="small">
<Descriptions.Item label="致命缺陷数">
<DescriptionsItem label="致命缺陷数">
{{ formData.criticalQuantity ?? 0 }}
</Descriptions.Item>
<Descriptions.Item label="严重缺陷数">
</DescriptionsItem>
<DescriptionsItem label="严重缺陷数">
{{ formData.majorQuantity ?? 0 }}
</Descriptions.Item>
<Descriptions.Item label="轻微缺陷数">
</DescriptionsItem>
<DescriptionsItem label="轻微缺陷数">
{{ formData.minorQuantity ?? 0 }}
</Descriptions.Item>
<Descriptions.Item label="致命缺陷率">
</DescriptionsItem>
<DescriptionsItem label="致命缺陷率">
{{ formData.criticalRate ?? 0 }}%
</Descriptions.Item>
<Descriptions.Item label="严重缺陷率">
</DescriptionsItem>
<DescriptionsItem label="严重缺陷率">
{{ formData.majorRate ?? 0 }}%
</Descriptions.Item>
<Descriptions.Item label="轻微缺陷率">
</DescriptionsItem>
<DescriptionsItem label="轻微缺陷率">
{{ formData.minorRate ?? 0 }}%
</Descriptions.Item>
</DescriptionsItem>
</Descriptions>
</div>
<Tabs

View File

@ -8,7 +8,7 @@ import { computed, ref } from 'vue';
import { confirm, useVbenModal } from '@vben/common-ui';
import { MesQcStatusEnum, MesQcTypeEnum } from '@vben/constants';
import { Button, Descriptions, message, Tabs } from 'antdv-next';
import { Button, Descriptions, DescriptionsItem, message, Tabs } from 'antdv-next';
import { useVbenForm } from '#/adapter/form';
import {
@ -188,24 +188,24 @@ const [Modal, modalApi] = useVbenModal({
<!-- 缺陷统计只读 -->
<div v-if="formData?.id" class="mx-4 mt-4">
<Descriptions title="缺陷情况" :column="3" bordered size="small">
<Descriptions.Item label="致命缺陷数">
<DescriptionsItem label="致命缺陷数">
{{ formData.criticalQuantity ?? 0 }}
</Descriptions.Item>
<Descriptions.Item label="严重缺陷数">
</DescriptionsItem>
<DescriptionsItem label="严重缺陷数">
{{ formData.majorQuantity ?? 0 }}
</Descriptions.Item>
<Descriptions.Item label="轻微缺陷数">
</DescriptionsItem>
<DescriptionsItem label="轻微缺陷数">
{{ formData.minorQuantity ?? 0 }}
</Descriptions.Item>
<Descriptions.Item label="致命缺陷率">
</DescriptionsItem>
<DescriptionsItem label="致命缺陷率">
{{ formData.criticalRate ?? 0 }}%
</Descriptions.Item>
<Descriptions.Item label="严重缺陷率">
</DescriptionsItem>
<DescriptionsItem label="严重缺陷率">
{{ formData.majorRate ?? 0 }}%
</Descriptions.Item>
<Descriptions.Item label="轻微缺陷率">
</DescriptionsItem>
<DescriptionsItem label="轻微缺陷率">
{{ formData.minorRate ?? 0 }}%
</Descriptions.Item>
</DescriptionsItem>
</Descriptions>
</div>
<Tabs