设备管理完善

This commit is contained in:
ChenYi 2025-07-28 16:50:59 +08:00
parent d88c93bdfb
commit b16a495cf1
8 changed files with 333 additions and 217 deletions

View File

@ -264,6 +264,7 @@
"OneNETManagement": { "OneNETManagement": {
"AccountName": "AccountName", "AccountName": "AccountName",
"PhoneNumber": "PhoneNumber", "PhoneNumber": "PhoneNumber",
"BelongingAccountName": "BelongingAccountName",
"AccountAccesskey": "AccountAccesskey", "AccountAccesskey": "AccountAccesskey",
"ProductCount": "ProductCount", "ProductCount": "ProductCount",
"OneNETAccountId": "OneNETAccountId", "OneNETAccountId": "OneNETAccountId",
@ -273,6 +274,7 @@
"IoTPlatformProductId": "IoTPlatformProductId", "IoTPlatformProductId": "IoTPlatformProductId",
"ProductName": "ProductName", "ProductName": "ProductName",
"ProductAccesskey": "ProductAccesskey", "ProductAccesskey": "ProductAccesskey",
"IsEncrypted": "IsEncrypted" "IsEncrypted": "IsEncrypted",
"BelongingProductName": "BelongingProductName"
} }
} }

View File

@ -53,5 +53,6 @@
"exportSuccess": "Data exported successfully", "exportSuccess": "Data exported successfully",
"exportFailed": "Data export failed", "exportFailed": "Data export failed",
"getDataFailed": "Failed to get data", "getDataFailed": "Failed to get data",
"PhoneNumberFormatError": "PhoneNumber Format Error" "PhoneNumberFormatError": "PhoneNumber Format Error",
"IoTPlatform": "IoTPlatform"
} }

View File

@ -265,6 +265,7 @@
}, },
"OneNETManagement": { "OneNETManagement": {
"AccountName": "账号名称", "AccountName": "账号名称",
"BelongingAccountName": "所属账号",
"PhoneNumber": "手机号码", "PhoneNumber": "手机号码",
"AccountAccesskey": "账户通信密钥", "AccountAccesskey": "账户通信密钥",
"ProductCount": "产品数量", "ProductCount": "产品数量",
@ -275,6 +276,7 @@
"IoTPlatformProductId": "物联网平台对应的产品Id", "IoTPlatformProductId": "物联网平台对应的产品Id",
"ProductName": "产品名称", "ProductName": "产品名称",
"ProductAccesskey": "产品访问密钥", "ProductAccesskey": "产品访问密钥",
"IsEncrypted": "是否加密" "IsEncrypted": "是否加密",
"BelongingProductName": "所属产品"
} }
} }

View File

@ -54,5 +54,6 @@
"exportFailed": "数据导出失败", "exportFailed": "数据导出失败",
"getDataFailed": "获取数据失败", "getDataFailed": "获取数据失败",
"IsEnabled": "是否启用", "IsEnabled": "是否启用",
"PhoneNumberFormatError": "手机号码格式错误" "PhoneNumberFormatError": "手机号码格式错误",
"IoTPlatform": "物联网平台"
} }

View File

@ -24,9 +24,7 @@ import { $t } from '#/locales';
import { import {
addDeviceFormSchema, addDeviceFormSchema,
editDeviceFormSchemaEdit, editDeviceFormSchemaEdit,
meterTypeOptions,
querySchema, querySchema,
rateOptions,
tableSchema, tableSchema,
} from './schema'; } from './schema';
@ -120,22 +118,19 @@ const [EditForm, editFormApi] = useVbenForm({
async function submit() { async function submit() {
const isEdit = !!editRow.value.id; const isEdit = !!editRow.value.id;
const formApi = isEdit ? editFormApi : addFormApi; const formApi = isEdit ? editFormApi : addFormApi;
// TODO: 使 const api = postAggregationDeviceCreateAsync; // 使
const api = postAggregationDeviceCreateAsync;
const { valid } = await formApi.validate(); const { valid } = await formApi.validate();
if (!valid) return; if (!valid) return;
const formValues = await formApi.getValues(); const formValues = await formApi.getValues();
const fetchParams: any = isEdit const fetchParams: any = isEdit
? { ? {
id: editRow.value.id, id: editRow.value.id,
...formValues, ...formValues,
password: formValues.password || '000000', }
}
: { : {
...formValues, ...formValues,
password: formValues.password || '000000', };
};
try { try {
userModalApi.setState({ loading: true, confirmLoading: true }); userModalApi.setState({ loading: true, confirmLoading: true });
@ -145,12 +140,18 @@ async function submit() {
editRow.value.id ? $t('common.editSuccess') : $t('common.addSuccess'), editRow.value.id ? $t('common.editSuccess') : $t('common.addSuccess'),
); );
userModalApi.close(); userModalApi.close();
editRow.value = {};
gridApi.reload(); gridApi.reload();
} else { } else {
Message.error( Message.error(
editRow.value.id ? $t('common.editFail') : $t('common.addFail'), editRow.value.id ? $t('common.editFail') : $t('common.addFail'),
); );
} }
} catch (error) {
console.error('设备操作失败:', error);
Message.error(
editRow.value.id ? $t('common.editFail') : $t('common.addFail'),
);
} finally { } finally {
userModalApi.setState({ loading: false, confirmLoading: false }); userModalApi.setState({ loading: false, confirmLoading: false });
} }
@ -164,13 +165,18 @@ async function onEdit(record: any) {
function onDel(row: any) { function onDel(row: any) {
Modal.confirm({ Modal.confirm({
title: `${$t('common.confirmDelete')}${row.meterName} ?`, title: `${$t('common.confirmDelete')}${row.deviceName || row.deviceAddress} ?`,
onOk: async () => { onOk: async () => {
const result = await postAggregationDeviceDeleteAsync({ body: { id: row.id } }); try {
if (result) { const result = await postAggregationDeviceDeleteAsync({ body: { id: row.id } });
gridApi.reload(); if (result.data) {
Message.success($t('common.deleteSuccess')); gridApi.reload();
} else { Message.success($t('common.deleteSuccess'));
} else {
Message.error($t('common.deleteFail'));
}
} catch (error) {
console.error('删除设备失败:', error);
Message.error($t('common.deleteFail')); Message.error($t('common.deleteFail'));
} }
}, },
@ -181,27 +187,31 @@ const toStatusData = (row: Record<string, any>) => {
router.push({ router.push({
path: '/iotdb/deviceData', path: '/iotdb/deviceData',
query: { query: {
DeviceType: row.meterType, DeviceType: row.ioTPlatform,
DeviceId: row.meterId, DeviceId: row.deviceAddress,
FocusAddress: row.focusAddress, FocusAddress: row.ioTPlatformDeviceOpenInfo,
DataBaseName: row.businessSystemName, DataBaseName: row.deviceName,
}, },
}); });
}; };
// //
const archivesIssued = async (row: Record<string, any>) => { const archivesIssued = async (row: Record<string, any>) => {
const result = await postDeviceInfoArchivesDown({ try {
body: { const result = await postDeviceInfoArchivesDown({
meterAddress: row.meterAddress, body: {
meterType: row.meterType, meterAddress: row.deviceAddress,
focusAddress: row.focusAddress, meterType: row.ioTPlatform,
}, focusAddress: row.ioTPlatformDeviceOpenInfo,
}); },
if (result) { });
gridApi.reload(); if (result.data) {
Message.success($t('common.success')); Message.success($t('common.operationSuccess'));
} else { } else {
Message.error($t('common.error')); Message.error($t('common.operationFail'));
}
} catch (error) {
console.error('档案下发失败:', error);
Message.error($t('common.operationFail'));
} }
}; };
const openAddModal = async () => { const openAddModal = async () => {

View File

@ -4,6 +4,10 @@ import { computed } from 'vue';
import { z } from '@vben/common-ui'; import { z } from '@vben/common-ui';
import {
getCommonGetSelectList,
postOneNetProductListAsync,
} from '#/api-client';
import { $t } from '#/locales'; import { $t } from '#/locales';
export const querySchema = computed(() => [ export const querySchema = computed(() => [
@ -13,40 +17,19 @@ export const querySchema = computed(() => [
label: $t('abp.deviceInfos.deviceAddress'), label: $t('abp.deviceInfos.deviceAddress'),
}, },
]); ]);
export const meterTypeOptions = [
export const ioTPlatformOptions = [
{ {
label: $t('abp.deviceInfos.ElectricityMeter'), label: 'OneNET',
value: 1, value: 1,
}, },
{ {
label: $t('abp.deviceInfos.waterMeter'), label: 'CTWing',
value: 2, value: 2,
}, },
{ {
label: $t('abp.deviceInfos.GasMeter'), label: 'Other',
value: 3, value: 0,
},
{
label: $t('abp.deviceInfos.HeatMeter'),
value: 4,
},
{
label: $t('abp.deviceInfos.WaterMeterFlowmeter'),
value: 5,
},
{
label: $t('abp.deviceInfos.GasMeterFlowmeter'),
value: 6,
},
];
export const rateOptions = [
{
label: $t('abp.deviceInfos.MultipleRate'),
value: false,
},
{
label: $t('abp.deviceInfos.SingleRate'),
value: true,
}, },
]; ];
export const tableSchema: any = computed((): VxeGridProps['columns'] => [ export const tableSchema: any = computed((): VxeGridProps['columns'] => [
@ -106,6 +89,93 @@ export const tableSchema: any = computed((): VxeGridProps['columns'] => [
]); ]);
export const addDeviceFormSchema: any = computed(() => [ export const addDeviceFormSchema: any = computed(() => [
{
component: 'ApiSelect',
fieldName: 'IoTPlatform',
label: $t('common.IoTPlatform'),
componentProps: {
api: getCommonGetSelectList,
params: {
query: {
typeName: 'IoTPlatformTypeEnum',
},
},
labelField: 'value',
valueField: 'key',
optionsPropName: 'options',
immediate: true,
afterFetch: (res: any) => {
// 确保返回的是数组格式
if (Array.isArray(res)) {
return res;
}
// 如果是包装在 items 中的,提取出来
if (res && Array.isArray(res.items)) {
return res.items;
}
// 如果是包装在 data 中的,提取出来
if (res && Array.isArray(res.data)) {
return res.data;
}
// 如果都不是,返回空数组
return [];
},
},
rules: z.string().min(1, {
message: `${$t('common.pleaseSelect')}${$t('common.IoTPlatform')}`,
}),
},
{
component: 'ApiSelect',
fieldName: 'ioTPlatformProductId',
label: $t('abp.OneNETManagement.BelongingProductName'),
componentProps: {
api: postOneNetProductListAsync,
params: {
body: {
pageIndex: 1,
pageSize: 1000,
},
},
labelField: 'ProductName',
valueField: 'ioTPlatformProductId',
immediate: true,
afterFetch: (res: any) => {
// 如果是 Axios 响应对象,提取 data
if (res && res.data) {
const data = res.data;
// 确保返回的是数组格式
if (Array.isArray(data)) {
return data;
}
// 如果是包装在 items 中的,提取出来
if (data && Array.isArray(data.items)) {
return data.items;
}
// 如果是包装在 data 中的,提取出来
if (data && Array.isArray(data.data)) {
return data.data;
}
}
// 如果都不是,返回空数组
return [];
},
placeholder: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.BelongingAccountName')}`,
},
rules: z.string().min(1, {
message: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.BelongingAccountName')}`,
}),
},
{
component: 'Input',
fieldName: 'deviceName',
label: $t('abp.deviceInfos.deviceName'),
rules: z.string().min(1, {
message: `${$t('common.pleaseInput')}${$t('abp.deviceInfos.deviceName')}`,
}),
},
{ {
component: 'Input', component: 'Input',
fieldName: 'deviceAddress', fieldName: 'deviceAddress',
@ -119,19 +189,101 @@ export const addDeviceFormSchema: any = computed(() => [
fieldName: 'platformPassword', fieldName: 'platformPassword',
label: $t('abp.deviceInfos.platformPassword'), label: $t('abp.deviceInfos.platformPassword'),
rules: z.string().min(1, { rules: z.string().min(1, {
message: `${$t('common.pleaseInput')}${$t('abp.deviceInfos.platformPassword')}`, message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.deviceInfos.platformPassword')}`,
}), }),
}, },
]); ]);
export const editDeviceFormSchemaEdit: any = computed(() => [ export const editDeviceFormSchemaEdit: any = computed(() => [
{
component: 'ApiSelect',
fieldName: 'IoTPlatform',
label: $t('common.IoTPlatform'),
componentProps: {
api: getCommonGetSelectList,
params: {
query: {
typeName: 'IoTPlatformTypeEnum',
},
},
labelField: 'value',
valueField: 'key',
optionsPropName: 'options',
immediate: true,
afterFetch: (res: any) => {
// 确保返回的是数组格式
if (Array.isArray(res)) {
return res;
}
// 如果是包装在 items 中的,提取出来
if (res && Array.isArray(res.items)) {
return res.items;
}
// 如果是包装在 data 中的,提取出来
if (res && Array.isArray(res.data)) {
return res.data;
}
// 如果都不是,返回空数组
return [];
},
},
},
{
component: 'ApiSelect',
fieldName: 'ioTPlatformProductId',
label: $t('abp.OneNETManagement.BelongingProductName'),
componentProps: {
api: postOneNetProductListAsync,
params: {
body: {
pageIndex: 1,
pageSize: 1000,
},
},
labelField: 'ProductName',
valueField: 'ioTPlatformProductId',
immediate: true,
afterFetch: (res: any) => {
// 如果是 Axios 响应对象,提取 data
if (res && res.data) {
const data = res.data;
// 确保返回的是数组格式
if (Array.isArray(data)) {
return data;
}
// 如果是包装在 items 中的,提取出来
if (data && Array.isArray(data.items)) {
return data.items;
}
// 如果是包装在 data 中的,提取出来
if (data && Array.isArray(data.data)) {
return data.data;
}
}
// 如果都不是,返回空数组
return [];
},
placeholder: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.BelongingAccountName')}`,
},
rules: z.string().min(1, {
message: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.BelongingAccountName')}`,
}),
},
{
component: 'Input',
fieldName: 'deviceName',
label: $t('abp.deviceInfos.deviceName'),
rules: z.string().min(1, {
message: `${$t('common.pleaseInput')}${$t('abp.deviceInfos.deviceName')}`,
}),
},
{ {
component: 'Input', component: 'Input',
fieldName: 'deviceAddress', fieldName: 'deviceAddress',
label: $t('abp.deviceInfos.deviceAddress'), label: $t('abp.deviceInfos.deviceAddress'),
rules: z.string().min(1, { disabled: true,
message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.deviceInfos.deviceAddress')}`,
}),
}, },
{ {
component: 'Input', component: 'Input',
@ -141,141 +293,4 @@ export const editDeviceFormSchemaEdit: any = computed(() => [
message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.deviceInfos.platformPassword')}`, message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.deviceInfos.platformPassword')}`,
}), }),
}, },
{
component: 'Select',
componentProps: {
allowClear: true,
options: meterTypeOptions,
placeholder: `${$t('common.pleaseSelect')}${$t('abp.deviceInfos.meterType')}`,
},
fieldName: 'meterType',
label: $t('abp.deviceInfos.meterType'),
rules: z
.number()
.min(1, {
message: `${$t('common.pleaseSelect')}${$t('abp.deviceInfos.meterType')}`,
})
.default(1),
},
{
component: 'Select',
componentProps: {
allowClear: true,
options: rateOptions,
placeholder: `${$t('common.pleaseSelect')}${$t('abp.deviceInfos.singleRate')}`,
},
dependencies: {
show(values: any) {
return values.meterType === 1;
},
rules(values: any) {
if (values.meterType === 1) {
return 'required';
}
return null;
},
triggerFields: ['meterType'],
},
fieldName: 'singleRate',
label: $t('abp.deviceInfos.singleRate'),
},
{
component: 'Switch',
componentProps: {
class: 'w-auto',
},
fieldName: 'selfDevelop',
label: $t('abp.deviceInfos.selfDevelop'),
},
{
component: 'Input',
fieldName: 'brandType',
label: $t('abp.deviceInfos.brandType'),
rules: z.string().optional(),
},
{
component: 'Switch',
componentProps: {
class: 'w-auto',
},
fieldName: 'dynamicPassword',
label: $t('abp.deviceInfos.dynamicPassword'),
},
{
component: 'Input',
fieldName: 'password',
label: $t('abp.deviceInfos.password'),
rules: z.string().optional(),
},
{
component: 'Switch',
componentProps: {
class: 'w-auto',
},
dependencies: {
show(values: any) {
return values.meterType === 2;
},
triggerFields: ['meterType'],
},
fieldName: 'haveValve',
label: $t('abp.deviceInfos.haveValve'),
},
{
component: 'Input',
fieldName: 'timesA',
label: $t('abp.deviceInfos.timesA'),
componentProps: {
allowClear: true,
placeholder: `${$t('common.pleaseInput')}${$t('abp.deviceInfos.timesA')}`,
},
dependencies: {
show(values: any) {
return values.meterType === 1;
},
triggerFields: ['meterType'],
},
rules: z
.string({
message: `${$t('common.pleaseInput')}${$t('abp.deviceInfos.timesA')}`,
})
.default('1'),
},
{
component: 'Input',
fieldName: 'timev',
label: $t('abp.deviceInfos.timev'),
componentProps: {
allowClear: true,
placeholder: `${$t('common.pleaseInput')}${$t('abp.deviceInfos.timev')}`,
},
dependencies: {
show(values: any) {
return values.meterType === 1;
},
triggerFields: ['meterType'],
},
rules: z
.string({
message: `${$t('common.pleaseInput')}${$t('abp.deviceInfos.timev')}`,
})
.default('1'),
},
{
component: 'Input',
fieldName: 'meteringCode',
label: $t('abp.deviceInfos.meteringCode'),
componentProps: {
allowClear: true,
placeholder: `${$t('common.pleaseInput')}${$t('abp.deviceInfos.meteringCode')}`,
},
rules: z
.string({
message: `${$t('common.pleaseInput')}${$t('abp.deviceInfos.meteringCode')}`,
})
.min(1, {
message: `${$t('common.MustGreaterTthan0')}`,
})
.default('1'),
},
]); ]);

View File

@ -47,7 +47,7 @@ export const querySchema = computed(() => [
api: getCommonGetSelectList, api: getCommonGetSelectList,
params: { params: {
query: { query: {
typeName: 'MeterTypeEnum' typeName: 'MeterTypeEnum',
}, },
}, },
labelField: 'value', labelField: 'value',
@ -80,7 +80,7 @@ export const querySchema = computed(() => [
api: getCommonGetSelectList, api: getCommonGetSelectList,
params: { params: {
query: { query: {
typeName: 'IoTDBDataTypeConst' typeName: 'IoTDBDataTypeConst',
}, },
}, },
labelField: 'value', labelField: 'value',

View File

@ -5,6 +5,7 @@ import { computed } from 'vue';
import { z } from '@vben/common-ui'; import { z } from '@vben/common-ui';
import { $t } from '#/locales'; import { $t } from '#/locales';
import { postOneNetAccountListAsync } from '#/api-client';
export const querySchema = computed(() => [ export const querySchema = computed(() => [
{ {
@ -57,6 +58,56 @@ export const tableSchema: any = computed((): VxeGridProps['columns'] => [
]); ]);
export const addProductFormSchema: any = computed(() => [ export const addProductFormSchema: any = computed(() => [
{
component: 'ApiSelect',
fieldName: 'oneNETAccountId',
label: $t('abp.OneNETManagement.BelongingAccountName'),
componentProps: {
api: postOneNetAccountListAsync,
params: {
body: {
pageIndex: 1,
pageSize: 1000,
},
},
labelField: 'accountName',
valueField: 'oneNETAccountId',
immediate: true,
afterFetch: (res: any) => {
console.log('ApiSelect afterFetch res:', res);
// 如果是 Axios 响应对象,提取 data
if (res && res.data) {
console.log('提取 res.data:', res.data);
const data = res.data;
// 确保返回的是数组格式
if (Array.isArray(data)) {
console.log('返回数组,长度:', data.length);
return data;
}
// 如果是包装在 items 中的,提取出来
if (data && Array.isArray(data.items)) {
console.log('返回items数组长度:', data.items.length);
return data.items;
}
// 如果是包装在 data 中的,提取出来
if (data && Array.isArray(data.data)) {
console.log('返回data数组长度:', data.data.length);
return data.data;
}
}
// 如果都不是,返回空数组
console.log('没有找到数组数据,返回空数组');
return [];
},
placeholder: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.BelongingAccountName')}`,
},
rules: z.string().min(1, {
message: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.BelongingAccountName')}`,
}),
},
{ {
component: 'Input', component: 'Input',
fieldName: 'oneNETProductId', fieldName: 'oneNETProductId',
@ -89,14 +140,6 @@ export const addProductFormSchema: any = computed(() => [
message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.OneNETManagement.ProductSecret')}`, message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.OneNETManagement.ProductSecret')}`,
}), }),
}, },
{
component: 'Input',
fieldName: 'accountName',
label: $t('abp.OneNETManagement.AccountName'),
rules: z.string().min(1, {
message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.OneNETManagement.AccountName')}`,
}),
},
{ {
component: 'Switch', component: 'Switch',
componentProps: { componentProps: {
@ -139,11 +182,53 @@ export const editProductFormSchemaEdit: any = computed(() => [
}), }),
}, },
{ {
component: 'Input', component: 'ApiSelect',
fieldName: 'accountName', fieldName: 'accountName',
label: $t('abp.OneNETManagement.AccountName'), label: $t('abp.OneNETManagement.AccountName'),
componentProps: {
api: postOneNetAccountListAsync,
params: {
body: {
pageIndex: 1,
pageSize: 1000,
},
},
labelField: 'accountName',
valueField: 'oneNETAccountId',
immediate: true,
afterFetch: (res: any) => {
console.log('ApiSelect afterFetch res:', res);
// 如果是 Axios 响应对象,提取 data
if (res && res.data) {
console.log('提取 res.data:', res.data);
const data = res.data;
// 确保返回的是数组格式
if (Array.isArray(data)) {
console.log('返回数组,长度:', data.length);
return data;
}
// 如果是包装在 items 中的,提取出来
if (data && Array.isArray(data.items)) {
console.log('返回items数组长度:', data.items.length);
return data.items;
}
// 如果是包装在 data 中的,提取出来
if (data && Array.isArray(data.data)) {
console.log('返回data数组长度:', data.data.length);
return data.data;
}
}
// 如果都不是,返回空数组
console.log('没有找到数组数据,返回空数组');
return [];
},
placeholder: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.AccountName')}`,
},
rules: z.string().min(1, { rules: z.string().min(1, {
message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.OneNETManagement.AccountName')}`, message: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.AccountName')}`,
}), }),
}, },
{ {