review:【antd/ele】【iot】代码迁移的 review
This commit is contained in:
@@ -63,17 +63,17 @@ const [DeviceImportFormModal, deviceImportFormModalApi] = useVbenModal({
|
|||||||
destroyOnClose: true,
|
destroyOnClose: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 搜索参数
|
const queryParams = ref({
|
||||||
const searchParams = ref({
|
|
||||||
deviceName: '',
|
deviceName: '',
|
||||||
nickname: '',
|
nickname: '',
|
||||||
productId: undefined as number | undefined,
|
productId: undefined as number | undefined,
|
||||||
deviceType: undefined as number | undefined,
|
deviceType: undefined as number | undefined,
|
||||||
status: undefined as number | undefined,
|
status: undefined as number | undefined,
|
||||||
groupId: undefined as number | undefined,
|
groupId: undefined as number | undefined,
|
||||||
});
|
}); // 搜索参数
|
||||||
|
|
||||||
// 获取字典选项
|
// 获取字典选项
|
||||||
|
// TODO @haohao:直接使用 getDictOptions 哈,不用包装方法;
|
||||||
const getIntDictOptions = (dictType: string) => {
|
const getIntDictOptions = (dictType: string) => {
|
||||||
return getDictOptions(dictType, 'number');
|
return getDictOptions(dictType, 'number');
|
||||||
};
|
};
|
||||||
@@ -81,21 +81,22 @@ const getIntDictOptions = (dictType: string) => {
|
|||||||
/** 搜索 */
|
/** 搜索 */
|
||||||
function handleSearch() {
|
function handleSearch() {
|
||||||
if (viewMode.value === 'list') {
|
if (viewMode.value === 'list') {
|
||||||
gridApi.formApi.setValues(searchParams.value);
|
gridApi.formApi.setValues(queryParams.value);
|
||||||
gridApi.query();
|
gridApi.query();
|
||||||
} else {
|
} else {
|
||||||
cardViewRef.value?.search(searchParams.value);
|
// todo @haohao:改成 query 方法,更统一;
|
||||||
|
cardViewRef.value?.search(queryParams.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 重置 */
|
/** 重置 */
|
||||||
function handleReset() {
|
function handleReset() {
|
||||||
searchParams.value.deviceName = '';
|
queryParams.value.deviceName = '';
|
||||||
searchParams.value.nickname = '';
|
queryParams.value.nickname = '';
|
||||||
searchParams.value.productId = undefined;
|
queryParams.value.productId = undefined;
|
||||||
searchParams.value.deviceType = undefined;
|
queryParams.value.deviceType = undefined;
|
||||||
searchParams.value.status = undefined;
|
queryParams.value.status = undefined;
|
||||||
searchParams.value.groupId = undefined;
|
queryParams.value.groupId = undefined;
|
||||||
handleSearch();
|
handleSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +111,7 @@ function handleRefresh() {
|
|||||||
|
|
||||||
/** 导出表格 */
|
/** 导出表格 */
|
||||||
async function handleExport() {
|
async function handleExport() {
|
||||||
const data = await exportDeviceExcel(searchParams.value);
|
const data = await exportDeviceExcel(queryParams.value);
|
||||||
downloadFileFromBlobPart({ fileName: '物联网设备.xls', source: data });
|
downloadFileFromBlobPart({ fileName: '物联网设备.xls', source: data });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +213,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
return await getDevicePage({
|
return await getDevicePage({
|
||||||
pageNo: page.currentPage,
|
pageNo: page.currentPage,
|
||||||
pageSize: page.pageSize,
|
pageSize: page.pageSize,
|
||||||
...searchParams.value,
|
...queryParams.value,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -238,7 +239,7 @@ onMounted(async () => {
|
|||||||
// 处理 productId 参数
|
// 处理 productId 参数
|
||||||
const { productId } = route.query;
|
const { productId } = route.query;
|
||||||
if (productId) {
|
if (productId) {
|
||||||
searchParams.value.productId = Number(productId);
|
queryParams.value.productId = Number(productId);
|
||||||
// 自动触发搜索
|
// 自动触发搜索
|
||||||
handleSearch();
|
handleSearch();
|
||||||
}
|
}
|
||||||
@@ -256,7 +257,7 @@ onMounted(async () => {
|
|||||||
<!-- 搜索表单 -->
|
<!-- 搜索表单 -->
|
||||||
<div class="mb-3 flex flex-wrap items-center gap-3">
|
<div class="mb-3 flex flex-wrap items-center gap-3">
|
||||||
<Select
|
<Select
|
||||||
v-model:value="searchParams.productId"
|
v-model:value="queryParams.productId"
|
||||||
placeholder="请选择产品"
|
placeholder="请选择产品"
|
||||||
allow-clear
|
allow-clear
|
||||||
style="width: 200px"
|
style="width: 200px"
|
||||||
@@ -270,21 +271,21 @@ onMounted(async () => {
|
|||||||
</Select.Option>
|
</Select.Option>
|
||||||
</Select>
|
</Select>
|
||||||
<Input
|
<Input
|
||||||
v-model:value="searchParams.deviceName"
|
v-model:value="queryParams.deviceName"
|
||||||
placeholder="请输入 DeviceName"
|
placeholder="请输入 DeviceName"
|
||||||
allow-clear
|
allow-clear
|
||||||
style="width: 200px"
|
style="width: 200px"
|
||||||
@press-enter="handleSearch"
|
@press-enter="handleSearch"
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
v-model:value="searchParams.nickname"
|
v-model:value="queryParams.nickname"
|
||||||
placeholder="请输入备注名称"
|
placeholder="请输入备注名称"
|
||||||
allow-clear
|
allow-clear
|
||||||
style="width: 200px"
|
style="width: 200px"
|
||||||
@press-enter="handleSearch"
|
@press-enter="handleSearch"
|
||||||
/>
|
/>
|
||||||
<Select
|
<Select
|
||||||
v-model:value="searchParams.deviceType"
|
v-model:value="queryParams.deviceType"
|
||||||
placeholder="请选择设备类型"
|
placeholder="请选择设备类型"
|
||||||
allow-clear
|
allow-clear
|
||||||
style="width: 200px"
|
style="width: 200px"
|
||||||
@@ -298,7 +299,7 @@ onMounted(async () => {
|
|||||||
</Select.Option>
|
</Select.Option>
|
||||||
</Select>
|
</Select>
|
||||||
<Select
|
<Select
|
||||||
v-model:value="searchParams.status"
|
v-model:value="queryParams.status"
|
||||||
placeholder="请选择设备状态"
|
placeholder="请选择设备状态"
|
||||||
allow-clear
|
allow-clear
|
||||||
style="width: 200px"
|
style="width: 200px"
|
||||||
@@ -312,7 +313,7 @@ onMounted(async () => {
|
|||||||
</Select.Option>
|
</Select.Option>
|
||||||
</Select>
|
</Select>
|
||||||
<Select
|
<Select
|
||||||
v-model:value="searchParams.groupId"
|
v-model:value="queryParams.groupId"
|
||||||
placeholder="请选择设备分组"
|
placeholder="请选择设备分组"
|
||||||
allow-clear
|
allow-clear
|
||||||
style="width: 200px"
|
style="width: 200px"
|
||||||
@@ -360,6 +361,7 @@ onMounted(async () => {
|
|||||||
auth: ['iot:device:import'],
|
auth: ['iot:device:import'],
|
||||||
onClick: handleImport,
|
onClick: handleImport,
|
||||||
},
|
},
|
||||||
|
// TODO @haohao:应该是选中后,才可用
|
||||||
{
|
{
|
||||||
label: '添加到分组',
|
label: '添加到分组',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
@@ -368,6 +370,7 @@ onMounted(async () => {
|
|||||||
ifShow: () => viewMode === 'list',
|
ifShow: () => viewMode === 'list',
|
||||||
onClick: handleAddToGroup,
|
onClick: handleAddToGroup,
|
||||||
},
|
},
|
||||||
|
// TODO @haohao:应该是选中后,才可用;然后,然后 danger 颜色;
|
||||||
{
|
{
|
||||||
label: '批量删除',
|
label: '批量删除',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
@@ -398,7 +401,7 @@ onMounted(async () => {
|
|||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Grid v-show="viewMode === 'list'">
|
<Grid table-title="设备列表" v-show="viewMode === 'list'">
|
||||||
<template #toolbar-tools>
|
<template #toolbar-tools>
|
||||||
<div></div>
|
<div></div>
|
||||||
</template>
|
</template>
|
||||||
@@ -469,7 +472,7 @@ onMounted(async () => {
|
|||||||
ref="cardViewRef"
|
ref="cardViewRef"
|
||||||
:products="products"
|
:products="products"
|
||||||
:device-groups="deviceGroups"
|
:device-groups="deviceGroups"
|
||||||
:search-params="searchParams"
|
:search-params="queryParams"
|
||||||
@create="handleCreate"
|
@create="handleCreate"
|
||||||
@edit="handleEdit"
|
@edit="handleEdit"
|
||||||
@delete="handleDelete"
|
@delete="handleDelete"
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
// TODO @haohao:product 的 card-view 的意见,这里看看要不要也改改下。
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { DICT_TYPE } from '@vben/constants';
|
import { DeviceStateEnum, DICT_TYPE } from '@vben/constants';
|
||||||
import { getDictLabel, getDictObj } from '@vben/hooks';
|
import { getDictLabel, getDictObj } from '@vben/hooks';
|
||||||
import { IconifyIcon } from '@vben/icons';
|
import { IconifyIcon } from '@vben/icons';
|
||||||
import { isValidColor, TinyColor } from '@vben/utils';
|
import { isValidColor, TinyColor } from '@vben/utils';
|
||||||
@@ -18,8 +19,6 @@ import {
|
|||||||
Tooltip,
|
Tooltip,
|
||||||
} from 'ant-design-vue';
|
} from 'ant-design-vue';
|
||||||
|
|
||||||
import { DeviceStateEnum } from '@vben/constants';
|
|
||||||
|
|
||||||
import { getDevicePage } from '#/api/iot/device/device';
|
import { getDevicePage } from '#/api/iot/device/device';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -180,6 +179,7 @@ function getDeviceTypeColor(deviceType: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 获取设备状态信息 */
|
/** 获取设备状态信息 */
|
||||||
|
// TODO @haohao:这里可以简化下么?体感看着有点复杂哈;
|
||||||
function getStatusInfo(state: null | number | string | undefined) {
|
function getStatusInfo(state: null | number | string | undefined) {
|
||||||
const parsedState = Number(state);
|
const parsedState = Number(state);
|
||||||
const hasNumericState = Number.isFinite(parsedState);
|
const hasNumericState = Number.isFinite(parsedState);
|
||||||
@@ -274,7 +274,7 @@ onMounted(() => {
|
|||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
<span class="info-label">所属产品</span>
|
<span class="info-label">所属产品</span>
|
||||||
<a
|
<a
|
||||||
class="info-value text-primary cursor-pointer"
|
class="info-value cursor-pointer text-primary"
|
||||||
@click="
|
@click="
|
||||||
(e) => {
|
(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -301,10 +301,7 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
<span class="info-label">Deviceid</span>
|
<span class="info-label">Deviceid</span>
|
||||||
<Tooltip
|
<Tooltip :title="item.Deviceid || item.id" placement="top">
|
||||||
:title="item.Deviceid || item.id"
|
|
||||||
placement="top"
|
|
||||||
>
|
|
||||||
<span class="info-value device-id cursor-pointer">
|
<span class="info-value device-id cursor-pointer">
|
||||||
{{ item.Deviceid || item.id }}
|
{{ item.Deviceid || item.id }}
|
||||||
</span>
|
</span>
|
||||||
@@ -359,7 +356,7 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 分页 -->
|
<!-- 分页 -->
|
||||||
<div v-if="list.length > 0" class="flex justify-end">
|
<div v-if="list.length > 0" class="mt-3 flex justify-end">
|
||||||
<Pagination
|
<Pagination
|
||||||
v-model:current="queryParams.pageNo"
|
v-model:current="queryParams.pageNo"
|
||||||
v-model:page-size="queryParams.pageSize"
|
v-model:page-size="queryParams.pageSize"
|
||||||
|
|||||||
@@ -7,11 +7,10 @@ import { onMounted, ref } from 'vue';
|
|||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { Page } from '@vben/common-ui';
|
import { Page } from '@vben/common-ui';
|
||||||
|
import { DeviceTypeEnum } from '@vben/constants';
|
||||||
|
|
||||||
import { message, Tabs } from 'ant-design-vue';
|
import { message, Tabs } from 'ant-design-vue';
|
||||||
|
|
||||||
import { DeviceTypeEnum } from '@vben/constants';
|
|
||||||
|
|
||||||
import { getDevice } from '#/api/iot/device/device';
|
import { getDevice } from '#/api/iot/device/device';
|
||||||
import { getProduct } from '#/api/iot/product/product';
|
import { getProduct } from '#/api/iot/product/product';
|
||||||
import { getThingModelListByProductId } from '#/api/iot/thingmodel';
|
import { getThingModelListByProductId } from '#/api/iot/thingmodel';
|
||||||
@@ -36,6 +35,8 @@ const device = ref<IotDeviceApi.Device>({} as IotDeviceApi.Device);
|
|||||||
const activeTab = ref('info');
|
const activeTab = ref('info');
|
||||||
const thingModelList = ref<ThingModelData[]>([]);
|
const thingModelList = ref<ThingModelData[]>([]);
|
||||||
|
|
||||||
|
// TODO @haohao:类似 device/detail/index.vue 挪出去哈。
|
||||||
|
|
||||||
/** 获取设备详情 */
|
/** 获取设备详情 */
|
||||||
async function getDeviceData(deviceId: number) {
|
async function getDeviceData(deviceId: number) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|||||||
@@ -56,14 +56,14 @@ const hasConfigData = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/** 启用编辑模式的函数 */
|
/** 启用编辑模式的函数 */
|
||||||
function enableEdit() {
|
function handleEdit() {
|
||||||
isEditing.value = true;
|
isEditing.value = true;
|
||||||
// 重新同步编辑器内容
|
// 重新同步编辑器内容
|
||||||
configString.value = JSON.stringify(config.value, null, 2);
|
configString.value = JSON.stringify(config.value, null, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 取消编辑的函数 */
|
/** 取消编辑的函数 */
|
||||||
function cancelEdit() {
|
function handleCancelEdit() {
|
||||||
try {
|
try {
|
||||||
config.value = props.device.config ? JSON.parse(props.device.config) : {};
|
config.value = props.device.config ? JSON.parse(props.device.config) : {};
|
||||||
configString.value = JSON.stringify(config.value, null, 2);
|
configString.value = JSON.stringify(config.value, null, 2);
|
||||||
@@ -84,29 +84,23 @@ async function saveConfig() {
|
|||||||
message.error({ content: 'JSON格式错误,请修正后再提交!' });
|
message.error({ content: 'JSON格式错误,请修正后再提交!' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// TODO @haohao:这里要不要做个类似下面的 pushLoading 避免重复提交;
|
||||||
await updateDeviceConfig();
|
await updateDeviceConfig();
|
||||||
isEditing.value = false;
|
isEditing.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 配置推送处理函数 */
|
/** 配置推送处理函数 */
|
||||||
async function handleConfigPush() {
|
async function handleConfigPush() {
|
||||||
|
pushLoading.value = true;
|
||||||
try {
|
try {
|
||||||
pushLoading.value = true;
|
|
||||||
|
|
||||||
// 调用配置推送接口
|
// 调用配置推送接口
|
||||||
await sendDeviceMessage({
|
await sendDeviceMessage({
|
||||||
deviceId: props.device.id!,
|
deviceId: props.device.id!,
|
||||||
method: IotDeviceMessageMethodEnum.CONFIG_PUSH.method,
|
method: IotDeviceMessageMethodEnum.CONFIG_PUSH.method,
|
||||||
params: config.value,
|
params: config.value,
|
||||||
});
|
});
|
||||||
|
// 提示成功
|
||||||
message.success({ content: '配置推送成功!' });
|
message.success({ content: '配置推送成功!' });
|
||||||
} catch (error) {
|
|
||||||
if (error !== 'cancel') {
|
|
||||||
message.error({ content: '配置推送失败!' });
|
|
||||||
console.error('配置推送错误:', error);
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
pushLoading.value = false;
|
pushLoading.value = false;
|
||||||
}
|
}
|
||||||
@@ -124,8 +118,6 @@ async function updateDeviceConfig() {
|
|||||||
message.success({ content: '更新成功!' });
|
message.success({ content: '更新成功!' });
|
||||||
// 触发 success 事件
|
// 触发 success 事件
|
||||||
emit('success');
|
emit('success');
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
@@ -143,8 +135,9 @@ async function updateDeviceConfig() {
|
|||||||
class="my-4"
|
class="my-4"
|
||||||
description="如需编辑文件,请点击下方编辑按钮"
|
description="如需编辑文件,请点击下方编辑按钮"
|
||||||
/>
|
/>
|
||||||
|
<!-- TODO @haohao:应该按钮,是在下方,可以参考 element-plus 的版本 -->
|
||||||
<div class="mt-5 text-center">
|
<div class="mt-5 text-center">
|
||||||
<Button v-if="isEditing" @click="cancelEdit">取消</Button>
|
<Button v-if="isEditing" @click="handleCancelEdit">取消</Button>
|
||||||
<Button
|
<Button
|
||||||
v-if="isEditing"
|
v-if="isEditing"
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -153,7 +146,7 @@ async function updateDeviceConfig() {
|
|||||||
>
|
>
|
||||||
保存
|
保存
|
||||||
</Button>
|
</Button>
|
||||||
<Button v-else @click="enableEdit">编辑</Button>
|
<Button v-else @click="handleEdit">编辑</Button>
|
||||||
<Button
|
<Button
|
||||||
v-if="!isEditing"
|
v-if="!isEditing"
|
||||||
type="primary"
|
type="primary"
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ import { getDeviceMessagePage } from '#/api/iot/device/device';
|
|||||||
import { DictTag } from '#/components/dict-tag';
|
import { DictTag } from '#/components/dict-tag';
|
||||||
import { IotDeviceMessageMethodEnum } from '#/views/iot/utils/constants';
|
import { IotDeviceMessageMethodEnum } from '#/views/iot/utils/constants';
|
||||||
|
|
||||||
|
// TODO @haohao:看看能不能调整成 Grid 风格~方便 element-plus 的迁移
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
deviceId: number;
|
deviceId: number;
|
||||||
}>();
|
}>();
|
||||||
|
|||||||
@@ -341,6 +341,7 @@ async function handleServiceInvoke(row: ThingModelData) {
|
|||||||
<template>
|
<template>
|
||||||
<ContentWrap>
|
<ContentWrap>
|
||||||
<!-- 上方:指令调试区域 -->
|
<!-- 上方:指令调试区域 -->
|
||||||
|
<!-- TODO @haohao:要不要改成左右; -->
|
||||||
<Card class="simulator-tabs mb-4">
|
<Card class="simulator-tabs mb-4">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { onMounted, ref } from 'vue';
|
|||||||
|
|
||||||
import { Card, Empty } from 'ant-design-vue';
|
import { Card, Empty } from 'ant-design-vue';
|
||||||
|
|
||||||
|
// TODO @haohao:这里要实现一把么?
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
deviceId: number;
|
deviceId: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<!-- 设备事件管理 -->
|
<!-- 设备事件管理 -->
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
// TODO @haohao:看看能不能用 Grid 实现下,方便 element-plus 迁移
|
||||||
import type { ThingModelData } from '#/api/iot/thingmodel';
|
import type { ThingModelData } from '#/api/iot/thingmodel';
|
||||||
|
|
||||||
import { computed, onMounted, reactive, ref } from 'vue';
|
import { computed, onMounted, reactive, ref } from 'vue';
|
||||||
|
|||||||
@@ -24,9 +24,8 @@ import {
|
|||||||
} from 'ant-design-vue';
|
} from 'ant-design-vue';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
import ShortcutDateRangePicker from '#/components/shortcut-date-range-picker/shortcut-date-range-picker.vue';
|
|
||||||
|
|
||||||
import { getHistoryDevicePropertyList } from '#/api/iot/device/device';
|
import { getHistoryDevicePropertyList } from '#/api/iot/device/device';
|
||||||
|
import ShortcutDateRangePicker from '#/components/shortcut-date-range-picker/shortcut-date-range-picker.vue';
|
||||||
import { IoTDataSpecsDataTypeEnum } from '#/views/iot/utils/constants';
|
import { IoTDataSpecsDataTypeEnum } from '#/views/iot/utils/constants';
|
||||||
|
|
||||||
/** IoT 设备属性历史数据详情 */
|
/** IoT 设备属性历史数据详情 */
|
||||||
@@ -43,16 +42,10 @@ const total = ref(0); // 总数据量
|
|||||||
const thingModelDataType = ref<string>(''); // 物模型数据类型
|
const thingModelDataType = ref<string>(''); // 物模型数据类型
|
||||||
const propertyIdentifier = ref<string>(''); // 属性标识符
|
const propertyIdentifier = ref<string>(''); // 属性标识符
|
||||||
|
|
||||||
/** 时间范围(仅日期,不包含时分秒) */
|
|
||||||
const dateRange = ref<[string, string]>([
|
const dateRange = ref<[string, string]>([
|
||||||
dayjs().subtract(6, 'day').format('YYYY-MM-DD'),
|
dayjs().subtract(6, 'day').format('YYYY-MM-DD'),
|
||||||
dayjs().format('YYYY-MM-DD'),
|
dayjs().format('YYYY-MM-DD'),
|
||||||
]);
|
]); // 时间范围(仅日期,不包含时分秒)
|
||||||
|
|
||||||
/** 将日期范围转换为带时分秒的格式 */
|
|
||||||
function formatDateRangeWithTime(dates: [string, string]): [string, string] {
|
|
||||||
return [`${dates[0]} 00:00:00`, `${dates[1]} 23:59:59`];
|
|
||||||
}
|
|
||||||
|
|
||||||
const queryParams = reactive({
|
const queryParams = reactive({
|
||||||
deviceId: -1,
|
deviceId: -1,
|
||||||
@@ -64,23 +57,21 @@ const queryParams = reactive({
|
|||||||
const chartRef = ref<EchartsUIType>();
|
const chartRef = ref<EchartsUIType>();
|
||||||
const { renderEcharts } = useEcharts(chartRef);
|
const { renderEcharts } = useEcharts(chartRef);
|
||||||
|
|
||||||
// 判断是否为复杂数据类型(struct 或 array)
|
|
||||||
const isComplexDataType = computed(() => {
|
const isComplexDataType = computed(() => {
|
||||||
if (!thingModelDataType.value) return false;
|
if (!thingModelDataType.value) return false;
|
||||||
return [
|
return [
|
||||||
IoTDataSpecsDataTypeEnum.ARRAY,
|
IoTDataSpecsDataTypeEnum.ARRAY,
|
||||||
IoTDataSpecsDataTypeEnum.STRUCT,
|
IoTDataSpecsDataTypeEnum.STRUCT,
|
||||||
].includes(thingModelDataType.value as any);
|
].includes(thingModelDataType.value as any);
|
||||||
});
|
}); // 判断是否为复杂数据类型(struct 或 array)
|
||||||
|
|
||||||
// 统计数据
|
|
||||||
const maxValue = computed(() => {
|
const maxValue = computed(() => {
|
||||||
if (isComplexDataType.value || list.value.length === 0) return '-';
|
if (isComplexDataType.value || list.value.length === 0) return '-';
|
||||||
const values = list.value
|
const values = list.value
|
||||||
.map((item) => Number(item.value))
|
.map((item) => Number(item.value))
|
||||||
.filter((v) => !Number.isNaN(v));
|
.filter((v) => !Number.isNaN(v));
|
||||||
return values.length > 0 ? Math.max(...values).toFixed(2) : '-';
|
return values.length > 0 ? Math.max(...values).toFixed(2) : '-';
|
||||||
});
|
}); // 统计数据
|
||||||
|
|
||||||
const minValue = computed(() => {
|
const minValue = computed(() => {
|
||||||
if (isComplexDataType.value || list.value.length === 0) return '-';
|
if (isComplexDataType.value || list.value.length === 0) return '-';
|
||||||
@@ -100,6 +91,11 @@ const avgValue = computed(() => {
|
|||||||
return (sum / values.length).toFixed(2);
|
return (sum / values.length).toFixed(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** 将日期范围转换为带时分秒的格式 */
|
||||||
|
function formatDateRangeWithTime(dates: [string, string]): [string, string] {
|
||||||
|
return [`${dates[0]} 00:00:00`, `${dates[1]} 23:59:59`];
|
||||||
|
}
|
||||||
|
|
||||||
// 表格列配置
|
// 表格列配置
|
||||||
const tableColumns = computed(() => [
|
const tableColumns = computed(() => [
|
||||||
{
|
{
|
||||||
@@ -409,7 +405,9 @@ defineExpose({ open }); // 提供 open 方法,用于打开弹窗
|
|||||||
<Space :size="12" class="w-full" wrap>
|
<Space :size="12" class="w-full" wrap>
|
||||||
<!-- 时间选择 -->
|
<!-- 时间选择 -->
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<span class="whitespace-nowrap text-sm text-gray-500">时间范围</span>
|
<span class="whitespace-nowrap text-sm text-gray-500">
|
||||||
|
时间范围
|
||||||
|
</span>
|
||||||
<ShortcutDateRangePicker @change="handleDateRangeChange" />
|
<ShortcutDateRangePicker @change="handleDateRangeChange" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -531,7 +529,7 @@ defineExpose({ open }); // 提供 open 方法,用于打开弹窗
|
|||||||
.chart-container,
|
.chart-container,
|
||||||
.table-container {
|
.table-container {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
background-color: hsl(var(--card));
|
background-color: hsl(var(--card)); // TODO @haohao:看看这个能不能 fix 下~ idea 爆红了;
|
||||||
border: 1px solid hsl(var(--border) / 60%);
|
border: 1px solid hsl(var(--border) / 60%);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<!-- 设备属性管理 -->
|
<!-- 设备属性管理 -->
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
// TODO @haohao:看看能不能用 Grid 实现下,方便 element-plus 迁移
|
||||||
import type { IotDeviceApi } from '#/api/iot/device/device';
|
import type { IotDeviceApi } from '#/api/iot/device/device';
|
||||||
|
|
||||||
import { onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue';
|
import { onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue';
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<!-- 设备服务调用 -->
|
<!-- 设备服务调用 -->
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
// TODO @haohao:看看能不能调整成 Grid 风格~方便 element-plus 的迁移
|
||||||
import type { ThingModelData } from '#/api/iot/thingmodel';
|
import type { ThingModelData } from '#/api/iot/thingmodel';
|
||||||
|
|
||||||
import { computed, onMounted, reactive, ref } from 'vue';
|
import { computed, onMounted, reactive, ref } from 'vue';
|
||||||
|
|||||||
@@ -8,11 +8,7 @@ import { useVbenModal } from '@vben/common-ui';
|
|||||||
import { message } from 'ant-design-vue';
|
import { message } from 'ant-design-vue';
|
||||||
|
|
||||||
import { useVbenForm } from '#/adapter/form';
|
import { useVbenForm } from '#/adapter/form';
|
||||||
import {
|
import { createDevice, getDevice, updateDevice } from '#/api/iot/device/device';
|
||||||
createDevice,
|
|
||||||
getDevice,
|
|
||||||
updateDevice,
|
|
||||||
} from '#/api/iot/device/device';
|
|
||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
import { useFormSchema } from '../data';
|
import { useFormSchema } from '../data';
|
||||||
@@ -40,7 +36,6 @@ const [Form, formApi] = useVbenForm({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [Modal, modalApi] = useVbenModal({
|
const [Modal, modalApi] = useVbenModal({
|
||||||
/** 提交表单 */
|
|
||||||
async onConfirm() {
|
async onConfirm() {
|
||||||
const { valid } = await formApi.validate();
|
const { valid } = await formApi.validate();
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
@@ -51,6 +46,7 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
const data = (await formApi.getValues()) as IotDeviceApi.Device;
|
const data = (await formApi.getValues()) as IotDeviceApi.Device;
|
||||||
try {
|
try {
|
||||||
await (formData.value?.id ? updateDevice(data) : createDevice(data));
|
await (formData.value?.id ? updateDevice(data) : createDevice(data));
|
||||||
|
// 关闭并提示
|
||||||
await modalApi.close();
|
await modalApi.close();
|
||||||
emit('success');
|
emit('success');
|
||||||
message.success($t('ui.actionMessage.operationSuccess'));
|
message.success($t('ui.actionMessage.operationSuccess'));
|
||||||
@@ -58,7 +54,6 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
modalApi.unlock();
|
modalApi.unlock();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/** 弹窗打开/关闭 */
|
|
||||||
async onOpenChange(isOpen: boolean) {
|
async onOpenChange(isOpen: boolean) {
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
formData.value = undefined;
|
formData.value = undefined;
|
||||||
@@ -68,6 +63,7 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
const data = modalApi.getData<IotDeviceApi.Device>();
|
const data = modalApi.getData<IotDeviceApi.Device>();
|
||||||
if (!data || !data.id) {
|
if (!data || !data.id) {
|
||||||
// 新增模式:设置默认值(如果需要)
|
// 新增模式:设置默认值(如果需要)
|
||||||
|
// TODO @haohao:是不是 return 就好啦;不用这里 undefined 啦;
|
||||||
formData.value = undefined;
|
formData.value = undefined;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ const [Form, formApi] = useVbenForm({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [Modal, modalApi] = useVbenModal({
|
const [Modal, modalApi] = useVbenModal({
|
||||||
/** 提交表单 */
|
|
||||||
async onConfirm() {
|
async onConfirm() {
|
||||||
const { valid } = await formApi.validate();
|
const { valid } = await formApi.validate();
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
@@ -43,6 +42,7 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
ids: deviceIds.value,
|
ids: deviceIds.value,
|
||||||
groupIds: data.groupIds as number[],
|
groupIds: data.groupIds as number[],
|
||||||
});
|
});
|
||||||
|
// 关闭并提示
|
||||||
await modalApi.close();
|
await modalApi.close();
|
||||||
emit('success');
|
emit('success');
|
||||||
message.success($t('ui.actionMessage.operationSuccess'));
|
message.success($t('ui.actionMessage.operationSuccess'));
|
||||||
@@ -50,7 +50,6 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
modalApi.unlock();
|
modalApi.unlock();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/** 弹窗打开/关闭 */
|
|
||||||
async onOpenChange(isOpen: boolean) {
|
async onOpenChange(isOpen: boolean) {
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
deviceIds.value = [];
|
deviceIds.value = [];
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
const data = modalApi.getData<IotProductCategoryApi.ProductCategory>();
|
const data = modalApi.getData<IotProductCategoryApi.ProductCategory>();
|
||||||
if (!data || !data.id) {
|
if (!data || !data.id) {
|
||||||
// 新增模式:设置默认值
|
// 新增模式:设置默认值
|
||||||
|
// TODO @AI:可以参考部门,进一步简化代码;通过 defaultValue 在 schema 里设置默认值
|
||||||
formData.value = undefined;
|
formData.value = undefined;
|
||||||
await formApi.setValues({
|
await formApi.setValues({
|
||||||
sort: 0,
|
sort: 0,
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ async function loadCategoryData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 初始化加载分类数据
|
// 初始化加载分类数据
|
||||||
|
// TODO @haohao:可以参考 /Users/yunai/Java/yudao-ui-admin-vben-v5/apps/web-antd/src/views/system/tenant/data.ts 简洁一点。
|
||||||
loadCategoryData();
|
loadCategoryData();
|
||||||
|
|
||||||
/** 新增/修改产品的表单 */
|
/** 新增/修改产品的表单 */
|
||||||
|
|||||||
@@ -7,13 +7,12 @@ import { onMounted, ref } from 'vue';
|
|||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { Page, useVbenModal } from '@vben/common-ui';
|
import { Page, useVbenModal } from '@vben/common-ui';
|
||||||
|
import { ProductStatusEnum } from '@vben/constants';
|
||||||
import { IconifyIcon } from '@vben/icons';
|
import { IconifyIcon } from '@vben/icons';
|
||||||
import { downloadFileFromBlobPart } from '@vben/utils';
|
import { downloadFileFromBlobPart } from '@vben/utils';
|
||||||
|
|
||||||
import { Button, Card, Input, message, Space } from 'ant-design-vue';
|
import { Button, Card, Input, message, Space } from 'ant-design-vue';
|
||||||
|
|
||||||
import { ProductStatusEnum } from '@vben/constants';
|
|
||||||
|
|
||||||
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||||
import { getSimpleProductCategoryList } from '#/api/iot/product/category';
|
import { getSimpleProductCategoryList } from '#/api/iot/product/category';
|
||||||
import {
|
import {
|
||||||
@@ -33,7 +32,7 @@ const router = useRouter();
|
|||||||
const categoryList = ref<IotProductCategoryApi.ProductCategory[]>([]);
|
const categoryList = ref<IotProductCategoryApi.ProductCategory[]>([]);
|
||||||
const viewMode = ref<'card' | 'list'>('card');
|
const viewMode = ref<'card' | 'list'>('card');
|
||||||
const cardViewRef = ref();
|
const cardViewRef = ref();
|
||||||
const searchParams = ref({
|
const queryParams = ref({
|
||||||
name: '',
|
name: '',
|
||||||
productKey: '',
|
productKey: '',
|
||||||
}); // 搜索参数
|
}); // 搜索参数
|
||||||
@@ -51,17 +50,18 @@ async function loadCategories() {
|
|||||||
/** 搜索产品 */
|
/** 搜索产品 */
|
||||||
function handleSearch() {
|
function handleSearch() {
|
||||||
if (viewMode.value === 'list') {
|
if (viewMode.value === 'list') {
|
||||||
gridApi.formApi.setValues(searchParams.value);
|
gridApi.formApi.setValues(queryParams.value);
|
||||||
gridApi.query();
|
gridApi.query();
|
||||||
} else {
|
} else {
|
||||||
cardViewRef.value?.search(searchParams.value);
|
// TODO @haohao:要不 search 也改成 query 方法,更统一一点哈。
|
||||||
|
cardViewRef.value?.search(queryParams.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 重置搜索 */
|
/** 重置搜索 */
|
||||||
function handleReset() {
|
function handleReset() {
|
||||||
searchParams.value.name = '';
|
queryParams.value.name = '';
|
||||||
searchParams.value.productKey = '';
|
queryParams.value.productKey = '';
|
||||||
handleSearch();
|
handleSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ function handleRefresh() {
|
|||||||
|
|
||||||
/** 导出表格 */
|
/** 导出表格 */
|
||||||
async function handleExport() {
|
async function handleExport() {
|
||||||
const data = await exportProduct(searchParams.value);
|
const data = await exportProduct(queryParams.value);
|
||||||
downloadFileFromBlobPart({ fileName: '产品列表.xls', source: data });
|
downloadFileFromBlobPart({ fileName: '产品列表.xls', source: data });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
return await getProductPage({
|
return await getProductPage({
|
||||||
pageNo: page.currentPage,
|
pageNo: page.currentPage,
|
||||||
pageSize: page.pageSize,
|
pageSize: page.pageSize,
|
||||||
...searchParams.value,
|
...queryParams.value,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -164,7 +164,7 @@ onMounted(() => {
|
|||||||
<!-- 搜索表单 -->
|
<!-- 搜索表单 -->
|
||||||
<div class="mb-3 flex items-center gap-3">
|
<div class="mb-3 flex items-center gap-3">
|
||||||
<Input
|
<Input
|
||||||
v-model:value="searchParams.name"
|
v-model:value="queryParams.name"
|
||||||
placeholder="请输入产品名称"
|
placeholder="请输入产品名称"
|
||||||
allow-clear
|
allow-clear
|
||||||
class="w-[220px]"
|
class="w-[220px]"
|
||||||
@@ -175,7 +175,7 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
</Input>
|
</Input>
|
||||||
<Input
|
<Input
|
||||||
v-model:value="searchParams.productKey"
|
v-model:value="queryParams.productKey"
|
||||||
placeholder="请输入产品标识"
|
placeholder="请输入产品标识"
|
||||||
allow-clear
|
allow-clear
|
||||||
class="w-[220px]"
|
class="w-[220px]"
|
||||||
@@ -230,7 +230,7 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Grid v-show="viewMode === 'list'">
|
<Grid table-title="产品列表" v-show="viewMode === 'list'">
|
||||||
<template #actions="{ row }">
|
<template #actions="{ row }">
|
||||||
<TableAction
|
<TableAction
|
||||||
:actions="[
|
:actions="[
|
||||||
@@ -271,14 +271,13 @@ onMounted(() => {
|
|||||||
v-show="viewMode === 'card'"
|
v-show="viewMode === 'card'"
|
||||||
ref="cardViewRef"
|
ref="cardViewRef"
|
||||||
:category-list="categoryList"
|
:category-list="categoryList"
|
||||||
:search-params="searchParams"
|
:search-params="queryParams"
|
||||||
@create="handleCreate"
|
@create="handleCreate"
|
||||||
@edit="handleEdit"
|
@edit="handleEdit"
|
||||||
@delete="handleDelete"
|
@delete="handleDelete"
|
||||||
@detail="openProductDetail"
|
@detail="openProductDetail"
|
||||||
@thing-model="openThingModel"
|
@thing-model="openThingModel"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</Page>
|
</Page>
|
||||||
</template>
|
</template>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
<span class="info-label">产品类型</span>
|
<span class="info-label">产品类型</span>
|
||||||
|
<!-- TODO @AI:这个要不完全用字典的 dict-tag? -->
|
||||||
<Tag
|
<Tag
|
||||||
:color="getDeviceTypeColor(item.deviceType)"
|
:color="getDeviceTypeColor(item.deviceType)"
|
||||||
class="info-tag m-0"
|
class="info-tag m-0"
|
||||||
@@ -231,7 +232,7 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 分页 -->
|
<!-- 分页 -->
|
||||||
<div v-if="list.length > 0" class="flex justify-end">
|
<div v-if="list.length > 0" class="mt-3 flex justify-end">
|
||||||
<Pagination
|
<Pagination
|
||||||
v-model:current="queryParams.pageNo"
|
v-model:current="queryParams.pageNo"
|
||||||
v-model:page-size="queryParams.pageSize"
|
v-model:page-size="queryParams.pageSize"
|
||||||
@@ -266,6 +267,7 @@ onMounted(() => {
|
|||||||
width: 36px;
|
width: 36px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
color: white;
|
color: white;
|
||||||
|
// TODO @haohao:这里的紫色,和下面的紫色按钮,看看能不能换下。嘿嘿,感觉 AI 比较喜欢用紫色,但是放现有的后台,有点突兀
|
||||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ const activeTab = ref('info');
|
|||||||
provide('product', product); // 提供产品信息给子组件
|
provide('product', product); // 提供产品信息给子组件
|
||||||
|
|
||||||
/** 获取产品详情 */
|
/** 获取产品详情 */
|
||||||
|
// TODO @haohao:因为 detail 是独立界面,所以不放在 modules 里,应该放在 web-antd/src/views/iot/product/product/detail/index.vue 里,更合理一些哈。
|
||||||
async function getProductData(productId: number) {
|
async function getProductData(productId: number) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -4,11 +4,10 @@ import type { IotProductApi } from '#/api/iot/product/product';
|
|||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { useVbenModal } from '@vben/common-ui';
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
|
import { ProductStatusEnum } from '@vben/constants';
|
||||||
|
|
||||||
import { Button, Card, Descriptions, message, Modal } from 'ant-design-vue';
|
import { Button, Card, Descriptions, message, Modal } from 'ant-design-vue';
|
||||||
|
|
||||||
import { ProductStatusEnum } from '@vben/constants';
|
|
||||||
|
|
||||||
import { updateProductStatus } from '#/api/iot/product/product';
|
import { updateProductStatus } from '#/api/iot/product/product';
|
||||||
|
|
||||||
import Form from '../../form.vue';
|
import Form from '../../form.vue';
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ const [Form, formApi] = useVbenForm({
|
|||||||
wrapperClass: 'grid-cols-2',
|
wrapperClass: 'grid-cols-2',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO @haohao:这个要不还是一行一个?这样样式好看点哈。
|
||||||
const [AdvancedForm, advancedFormApi] = useVbenForm({
|
const [AdvancedForm, advancedFormApi] = useVbenForm({
|
||||||
commonConfig: {
|
commonConfig: {
|
||||||
componentProps: { class: 'w-full' },
|
componentProps: { class: 'w-full' },
|
||||||
@@ -51,10 +52,10 @@ const [AdvancedForm, advancedFormApi] = useVbenForm({
|
|||||||
});
|
});
|
||||||
|
|
||||||
/** 基础表单需要 formApi 引用,所以通过 setState 设置 schema */
|
/** 基础表单需要 formApi 引用,所以通过 setState 设置 schema */
|
||||||
|
// TODO haohao:@haohao:要不要把 generateProductKey 拿到这个 vue 里,作为参数传递到 useBasicFormSchema 里?
|
||||||
formApi.setState({ schema: useBasicFormSchema(formApi) });
|
formApi.setState({ schema: useBasicFormSchema(formApi) });
|
||||||
|
|
||||||
const [Modal, modalApi] = useVbenModal({
|
const [Modal, modalApi] = useVbenModal({
|
||||||
/** 提交表单 */
|
|
||||||
async onConfirm() {
|
async onConfirm() {
|
||||||
const { valid } = await formApi.validate();
|
const { valid } = await formApi.validate();
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
@@ -63,6 +64,7 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
modalApi.lock();
|
modalApi.lock();
|
||||||
// 合并两个表单的值
|
// 合并两个表单的值
|
||||||
const basicValues = await formApi.getValues();
|
const basicValues = await formApi.getValues();
|
||||||
|
// TODO @haohao:有 linter 修复下;“formData.value?.id”;另外,这里直接两个表单合并,是不是就可以了呀?因为 2 个 schema 本身不同,字段就不同,不会冲突。
|
||||||
const advancedValues = activeKey.value.includes('advanced')
|
const advancedValues = activeKey.value.includes('advanced')
|
||||||
? await advancedFormApi.getValues()
|
? await advancedFormApi.getValues()
|
||||||
: formData.value?.id
|
: formData.value?.id
|
||||||
@@ -85,7 +87,6 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
modalApi.unlock();
|
modalApi.unlock();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/** 弹窗打开/关闭 */
|
|
||||||
async onOpenChange(isOpen: boolean) {
|
async onOpenChange(isOpen: boolean) {
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
formData.value = undefined;
|
formData.value = undefined;
|
||||||
@@ -96,9 +97,11 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
const data = modalApi.getData<IotProductApi.Product>();
|
const data = modalApi.getData<IotProductApi.Product>();
|
||||||
if (!data || !data.id) {
|
if (!data || !data.id) {
|
||||||
// 新增:设置默认值
|
// 新增:设置默认值
|
||||||
|
// TODO @AI:
|
||||||
await formApi.setValues({
|
await formApi.setValues({
|
||||||
|
// TODO @haohao:要不要把 generateProductKey 拿到这个 vue 里,作为参数传递到 useBasicFormSchema 里?
|
||||||
productKey: generateProductKey(),
|
productKey: generateProductKey(),
|
||||||
status: 0,
|
status: 0, // TODO @haohao:通过 defaultValue 即可;
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -108,12 +111,15 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
formData.value = await getProduct(data.id);
|
formData.value = await getProduct(data.id);
|
||||||
await formApi.setValues(formData.value);
|
await formApi.setValues(formData.value);
|
||||||
// 设置高级表单(不等待)
|
// 设置高级表单(不等待)
|
||||||
|
// TODO @haohao:直接把 formData 传过去?没关系的哈。因为会 filter 掉不存在的值,可以试试哈。
|
||||||
|
// TODO @haohao:这里是不是要 await 下呀?有黄色的告警;
|
||||||
advancedFormApi.setValues({
|
advancedFormApi.setValues({
|
||||||
icon: formData.value.icon,
|
icon: formData.value.icon,
|
||||||
picUrl: formData.value.picUrl,
|
picUrl: formData.value.picUrl,
|
||||||
description: formData.value.description,
|
description: formData.value.description,
|
||||||
});
|
});
|
||||||
// 有高级字段时自动展开
|
// 有高级字段时自动展开
|
||||||
|
// TODO @haohao:默认不用展开哈。
|
||||||
if (
|
if (
|
||||||
formData.value.icon ||
|
formData.value.icon ||
|
||||||
formData.value.picUrl ||
|
formData.value.picUrl ||
|
||||||
|
|||||||
Reference in New Issue
Block a user