CTWing界面

This commit is contained in:
ChenYi 2025-07-30 11:29:39 +08:00
parent c6b8339a02
commit 73c66e6b38
9 changed files with 1898 additions and 2236 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -281,5 +281,27 @@
"IoTPlatformProductCreateTime": "ProductCreateTime", "IoTPlatformProductCreateTime": "ProductCreateTime",
"CreationTime": "CreationTime", "CreationTime": "CreationTime",
"LastModificationTime": "LastModificationTime" "LastModificationTime": "LastModificationTime"
},
"CTWingManagement": {
"AccountName": "AccountName",
"PhoneNumber": "PhoneNumber",
"BelongingAccountName": "BelongingAccountName",
"AccountAccesskey": "AccountAccesskey",
"ProductCount": "ProductCount",
"CTWingAccountId": "CTWingAccountId",
"CTWingProductId": "CTWingProductId",
"IoTPlatformProductId": "IoTPlatformProductId",
"ProductName": "ProductName",
"ProductAccesskey": "ProductAccesskey",
"IsEncrypted": "IsEncrypted",
"BelongingProductName": "Belonging ProductName",
"CommunicationAddress": "Communication Address",
"CommunicationAddressTLS": "TLS Communication Address",
"DeviceThingModelFileName": "DeviceThingModelFileName",
"IoTPlatformProductUpdateTime": "ProductUpdateTime",
"IoTPlatformProductCreateTime": "ProductCreateTime",
"CreationTime": "CreationTime",
"LastModificationTime": "LastModificationTime",
"CannotDeleteAccountWithProducts": "Cannot delete account with products"
} }
} }

View File

@ -283,5 +283,27 @@
"IoTPlatformProductCreateTime": "平台创建时间", "IoTPlatformProductCreateTime": "平台创建时间",
"CreationTime": "创建时间", "CreationTime": "创建时间",
"LastModificationTime": "更新时间" "LastModificationTime": "更新时间"
},
"CTWingManagement": {
"AccountName": "账号名称",
"BelongingAccountName": "所属账号",
"PhoneNumber": "手机号码",
"AccountAccesskey": "账户通信密钥",
"ProductCount": "产品数量",
"CTWingAccountId": "CTWing账户Id",
"CTWingProductId": "CTWing产品Id",
"IoTPlatformProductId": "物联网平台对应的产品Id",
"ProductName": "产品名称",
"ProductAccesskey": "产品密钥",
"IsEncrypted": "是否加密",
"BelongingProductName": "所属产品",
"CommunicationAddress": "通讯地址",
"CommunicationAddressTLS": "TLS通讯地址",
"DeviceThingModelFileName": "物模型文件",
"IoTPlatformProductUpdateTime": "平台更新时间",
"IoTPlatformProductCreateTime": "平台创建时间",
"CreationTime": "创建时间",
"LastModificationTime": "更新时间",
"CannotDeleteAccountWithProducts": "该账号下存在产品,无法删除"
} }
} }

View File

@ -2,35 +2,33 @@
import type { VbenFormProps } from '#/adapter/form'; import type { VbenFormProps } from '#/adapter/form';
import type { VxeGridProps } from '#/adapter/vxe-table'; import type { VxeGridProps } from '#/adapter/vxe-table';
import { h, ref } from 'vue'; import { 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 { message as Message, Modal, Tag } from 'ant-design-vue'; import { message as Message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form'; import { useVbenForm } from '#/adapter/form';
import { useVbenVxeGrid } from '#/adapter/vxe-table'; import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { import {
postDeviceInfoPage, postCtWingAccountDeleteAsync,
postAggregationDeviceDeleteAsync, postCtWingAccountListAsync,
postDeviceInfoPage, postCtWingAccountInsertAsync,
postAggregationDeviceCreateAsync, postCtWingAccountModifyAsync,
} from '#/api-client'; } from '#/api-client';
import { TableAction } from '#/components/table-action'; import { TableAction } from '#/components/table-action';
import { $t } from '#/locales'; import { $t } from '#/locales';
import { import {
addUserFormSchema, addAccountFormSchema,
editUserFormSchemaEdit, editAccountFormSchemaEdit,
meterTypeOptions,
querySchema, querySchema,
rateOptions,
tableSchema, tableSchema,
} from './schema'; } from './schema';
defineOptions({ defineOptions({
name: 'AbpUser', name: 'CTWingAccount',
}); });
const router = useRouter(); const router = useRouter();
@ -55,7 +53,7 @@ const gridOptions: VxeGridProps<any> = {
proxyConfig: { proxyConfig: {
ajax: { ajax: {
query: async ({ page }, formValues) => { query: async ({ page }, formValues) => {
const { data } = await postDeviceInfoPage({ const { data } = await postCtWingAccountListAsync({
body: { body: {
pageIndex: page.currentPage, pageIndex: page.currentPage,
pageSize: page.pageSize, pageSize: page.pageSize,
@ -75,7 +73,7 @@ const [UserModal, userModalApi] = useVbenModal({
draggable: true, draggable: true,
onConfirm: submit, onConfirm: submit,
onBeforeClose: () => { onBeforeClose: () => {
editRow.value = {}; //
return true; return true;
}, },
}); });
@ -91,7 +89,7 @@ const [AddForm, addFormApi] = useVbenForm({
}, },
}, },
layout: 'horizontal', layout: 'horizontal',
schema: addUserFormSchema.value, schema: addAccountFormSchema.value,
showCollapseButton: false, showCollapseButton: false,
showDefaultActions: false, showDefaultActions: false,
wrapperClass: 'grid-cols-2', wrapperClass: 'grid-cols-2',
@ -109,7 +107,7 @@ const [EditForm, editFormApi] = useVbenForm({
}, },
// //
layout: 'horizontal', layout: 'horizontal',
schema: editUserFormSchemaEdit.value, schema: editAccountFormSchemaEdit.value,
showCollapseButton: false, showCollapseButton: false,
showDefaultActions: false, showDefaultActions: false,
wrapperClass: 'grid-cols-2', wrapperClass: 'grid-cols-2',
@ -119,8 +117,7 @@ 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 = isEdit ? postCtWingAccountModifyAsync : postCtWingAccountInsertAsync;
const api = postAggregationDeviceCreateAsync;
const { valid } = await formApi.validate(); const { valid } = await formApi.validate();
if (!valid) return; if (!valid) return;
@ -129,11 +126,9 @@ async function submit() {
? { ? {
id: editRow.value.id, id: editRow.value.id,
...formValues, ...formValues,
password: formValues.password || '000000',
} }
: { : {
...formValues, ...formValues,
password: formValues.password || '000000',
}; };
try { try {
@ -144,6 +139,7 @@ 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(
@ -161,35 +157,30 @@ async function onEdit(record: any) {
editFormApi.setValues({ ...record }); editFormApi.setValues({ ...record });
} }
function onDel(row: any) {
Modal.confirm({
title: `${$t('common.confirmDelete')}${row.meterName} ?`,
onOk: async () => {
const result = await postAggregationDeviceDeleteAsync({ body: { id: row.id } });
if (result) {
gridApi.reload();
Message.success($t('common.deleteSuccess'));
} else {
Message.error($t('common.deleteFail'));
}
},
});
}
const toStatusData = (row: Record<string, any>) => {
// 使
router.push({
path: '/iotdb/point',
query: {
DeviceType: row.meterType,
DeviceId: row.meterId,
FocusAddress: row.focusAddress,
},
});
};
const openAddModal = async () => { const openAddModal = async () => {
editRow.value = {}; editRow.value = {};
userModalApi.open(); userModalApi.open();
}; };
//
async function onDel(record: any) {
if (record.productCount > 0) {
Message.warning($t('abp.CTWingManagement.CannotDeleteAccountWithProducts'));
return;
}
try {
const resp = await postCtWingAccountDeleteAsync({ body: { id: record.id } });
if (resp.data) {
Message.success($t('common.deleteSuccess'));
gridApi.reload();
} else {
Message.error($t('common.deleteFail'));
}
} catch {
Message.error($t('common.deleteFail'));
}
}
</script> </script>
<template> <template>
@ -209,57 +200,6 @@ const openAddModal = async () => {
/> />
</template> </template>
<template #isMeterType="{ row }">
{{ meterTypeOptions[row.meterType - 1]?.label }}
</template>
<template #isSingleRate="{ row }">
{{ rateOptions.find((item) => item.value === row.singleRate)?.label }}
</template>
<template #isArchiveStatus="{ row }">
{{
row.archiveStatus ? $t('common.Issued') : $t('common.Undistributed')
}}
</template>
<template #isTripState="{ row }">
{{ row.tripState ? $t('common.SwitchOff') : $t('common.Closing') }}
</template>
<template #isHaveValve="{ row }">
<component
:is="
h(Tag, { color: row.haveValve ? 'green' : 'red' }, () =>
row.haveValve ? $t('common.yes') : $t('common.no'),
)
"
/>
</template>
<template #isSelfDevelop="{ row }">
<component
:is="
h(Tag, { color: row.selfDevelop ? 'green' : 'red' }, () =>
row.selfDevelop ? $t('common.yes') : $t('common.no'),
)
"
/>
</template>
<template #isDynamicPassword="{ row }">
<component
:is="
h(Tag, { color: row.dynamicPassword ? 'green' : 'red' }, () =>
row.dynamicPassword ? $t('common.yes') : $t('common.no'),
)
"
/>
</template>
<template #isEnable="{ row }">
<component
:is="
h(Tag, { color: row.enabled ? 'green' : 'red' }, () =>
row.enabled ? $t('common.yes') : $t('common.no'),
)
"
/>
</template>
<template #action="{ row }"> <template #action="{ row }">
<TableAction <TableAction
:actions="[ :actions="[
@ -277,25 +217,15 @@ const openAddModal = async () => {
icon: 'ant-design:delete-outlined', icon: 'ant-design:delete-outlined',
type: 'primary', type: 'primary',
auth: ['AbpIdentity.Users.Delete'], auth: ['AbpIdentity.Users.Delete'],
disabled: row.productCount > 0,
popConfirm: { popConfirm: {
title: $t('common.askConfirmDelete'), title:
row.productCount > 0
? $t('abp.CTWingManagement.CannotDeleteAccountWithProducts')
: $t('common.askConfirmDelete'),
confirm: onDel.bind(null, row), confirm: onDel.bind(null, row),
}, },
}, },
{
label: $t('abp.meters.pointData'),
icon: 'ant-design:profile-outlined',
type: 'primary',
auth: ['AbpIdentity.Users.Delete'],
onClick: toStatusData.bind(null, row),
},
{
label: $t('abp.meters.archivesIssued'),
icon: 'ant-design:cloud-download-outlined',
type: 'primary',
auth: ['AbpIdentity.Users.Delete'],
onClick: archivesIssued.bind(null, row),
},
]" ]"
/> />
</template> </template>

View File

@ -9,109 +9,37 @@ import { $t } from '#/locales';
export const querySchema = computed(() => [ export const querySchema = computed(() => [
{ {
component: 'Input', component: 'Input',
fieldName: 'meterAddress', fieldName: 'phoneNumber',
label: $t('abp.meters.meterAddress'), label: $t('abp.CTWingManagement.PhoneNumber'),
}, },
]); ]);
export const meterTypeOptions = [
{
label: $t('abp.meters.ElectricityMeter'),
value: 1,
},
{
label: $t('abp.meters.waterMeter'),
value: 2,
},
{
label: $t('abp.meters.GasMeter'),
value: 3,
},
{
label: $t('abp.meters.HeatMeter'),
value: 4,
},
{
label: $t('abp.meters.WaterMeterFlowmeter'),
value: 5,
},
{
label: $t('abp.meters.GasMeterFlowmeter'),
value: 6,
},
];
export const rateOptions = [
{
label: $t('abp.meters.MultipleRate'),
value: false,
},
{
label: $t('abp.meters.SingleRate'),
value: true,
},
];
export const tableSchema: any = computed((): VxeGridProps['columns'] => [ export const tableSchema: any = computed((): VxeGridProps['columns'] => [
{ title: $t('common.seq'), type: 'seq', width: 50 }, { title: $t('common.seq'), type: 'seq', width: 50 },
{ field: 'meterName', title: $t('abp.meters.meterName'), minWidth: '150' },
{ {
field: 'meterAddress', field: 'ctWingAccountId',
title: $t('abp.meters.meterAddress'), title: $t('abp.CTWingManagement.CTWingAccountId'),
minWidth: '150', minWidth: '150',
}, },
{ {
field: 'meterType', field: 'accountName',
title: $t('abp.meters.meterType'), title: $t('abp.CTWingManagement.AccountName'),
minWidth: '150', minWidth: '150',
slots: { default: 'isMeterType' },
}, },
{ {
field: 'dynamicPassword', field: 'phoneNumber',
title: $t('abp.meters.dynamicPassword'), title: $t('abp.CTWingManagement.PhoneNumber'),
minWidth: '150', minWidth: '150',
slots: { default: 'isDynamicPassword' },
}, },
{ {
field: 'password', field: 'accountAccesskey',
title: $t('abp.meters.password'), title: $t('abp.CTWingManagement.AccountAccesskey'),
minWidth: '100', minWidth: '150',
}, },
{ {
field: 'singleRate', field: 'productCount',
title: $t('abp.meters.singleRate'), title: $t('abp.CTWingManagement.ProductCount'),
minWidth: '150', minWidth: '150',
slots: { default: 'isSingleRate' },
},
{
field: 'selfDevelop',
title: $t('abp.meters.selfDevelop'),
minWidth: '150',
slots: { default: 'isSelfDevelop' },
},
{ field: 'brandType', title: $t('abp.meters.brandType'), minWidth: '150' },
{
field: 'archiveStatus',
title: $t('abp.meters.archiveStatus'),
minWidth: '150',
slots: { default: 'isArchiveStatus' },
},
{
field: 'tripState',
title: $t('abp.meters.tripState'),
minWidth: '150',
slots: { default: 'isTripState' },
},
{ field: 'timesA', title: $t('abp.meters.timesA'), minWidth: '100' },
{ field: 'timev', title: $t('abp.meters.timev'), minWidth: '100' },
{
field: 'haveValve',
title: $t('abp.meters.haveValve'),
minWidth: '150',
slots: { default: 'isHaveValve' },
},
{
field: 'enabled',
title: $t('common.isEnable'),
minWidth: '150',
slots: { default: 'isEnable' },
}, },
{ {
title: $t('common.action'), title: $t('common.action'),
@ -122,321 +50,80 @@ export const tableSchema: any = computed((): VxeGridProps['columns'] => [
}, },
]); ]);
export const addUserFormSchema: any = computed(() => [ export const addAccountFormSchema: any = computed(() => [
{ {
component: 'Input', component: 'Input',
fieldName: 'meterName', fieldName: 'ctWingAccountId',
label: $t('abp.meters.meterName'), label: $t('abp.CTWingManagement.CTWingAccountId'),
rules: z.string().min(1, { rules: z.string().min(1, {
message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.meters.meterName')}`, message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.CTWingManagement.CTWingAccountId')}`,
}), }),
}, },
{ {
component: 'Input', component: 'Input',
fieldName: 'meterAddress', fieldName: 'accountName',
label: $t('abp.meters.meterAddress'), label: $t('abp.CTWingManagement.AccountName'),
rules: z.string().min(1, {
message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.CTWingManagement.AccountName')}`,
}),
},
{
component: 'Input',
fieldName: 'accountAccesskey',
label: $t('abp.CTWingManagement.AccountAccesskey'),
rules: z.string().min(1, {
message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.CTWingManagement.AccountAccesskey')}`,
}),
},
{
component: 'Input',
fieldName: 'phoneNumber',
label: $t('abp.CTWingManagement.PhoneNumber'),
rules: z rules: z
.string() .string()
.min(1, { .min(1, {
message: `${$t('common.pleaseInput')}${$t('common.numberType')}${$t('abp.meters.meterAddress')}`, message: `${$t('common.pleaseInput')}${$t('abp.CTWingManagement.PhoneNumber')}`,
}) })
.refine((value) => /^\d+$/.test(value), { .refine((value) => /^1[3-9]\d{9}$/.test(value), {
message: $t('abp.meters.checkmeterAddress'), message: $t('common.PhoneNumberFormatError'),
}), }),
}, },
{
component: 'Select',
componentProps: {
allowClear: true,
options: meterTypeOptions,
placeholder: `${$t('common.pleaseSelect')}${$t('abp.meters.meterType')}`,
},
fieldName: 'meterType',
label: $t('abp.meters.meterType'),
rules: z
.number()
.min(1, {
message: `${$t('common.pleaseSelect')}${$t('abp.meters.meterType')}`,
})
.default(1),
},
{
component: 'Select',
componentProps: {
allowClear: true,
options: rateOptions,
placeholder: `${$t('common.pleaseSelect')}${$t('abp.meters.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.meters.singleRate'),
},
{
component: 'Switch',
componentProps: {
class: 'w-auto',
},
fieldName: 'selfDevelop',
label: $t('abp.meters.selfDevelop'),
},
{
component: 'Input',
fieldName: 'brandType',
label: $t('abp.meters.brandType'),
rules: z.string().optional(),
},
{
component: 'Switch',
componentProps: {
class: 'w-auto',
},
fieldName: 'dynamicPassword',
label: $t('abp.meters.dynamicPassword'),
},
{
component: 'Input',
fieldName: 'password',
label: $t('abp.meters.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.meters.haveValve'),
},
{
component: 'Input',
fieldName: 'timesA',
label: $t('abp.meters.timesA'),
componentProps: {
allowClear: true,
placeholder: `${$t('common.pleaseInput')}${$t('abp.meters.timesA')}`,
},
dependencies: {
show(values: any) {
return values.meterType === 1;
},
triggerFields: ['meterType'],
},
rules: z
.string({
message: `${$t('common.pleaseInput')}${$t('abp.meters.timesA')}`,
})
.default('1'),
},
{
component: 'Input',
fieldName: 'timev',
label: $t('abp.meters.timev'),
componentProps: {
allowClear: true,
placeholder: `${$t('common.pleaseInput')}${$t('abp.meters.timev')}`,
},
dependencies: {
show(values: any) {
return values.meterType === 1;
},
triggerFields: ['meterType'],
},
rules: z
.string({
message: `${$t('common.pleaseInput')}${$t('abp.meters.timesA')}`,
})
.default('1'),
},
{
component: 'Input',
fieldName: 'meteringCode',
label: $t('abp.meters.meteringCode'),
componentProps: {
allowClear: true,
placeholder: `${$t('common.pleaseInput')}${$t('abp.meters.meteringCode')}`,
},
rules: z
.string({
message: `${$t('common.pleaseInput')}${$t('abp.meters.meteringCode')}`,
})
.default('1'),
},
]); ]);
export const editUserFormSchemaEdit: any = computed(() => [ export const editAccountFormSchemaEdit: any = computed(() => [
{ {
component: 'Input', component: 'Input',
fieldName: 'meterName', fieldName: 'ctWingAccountId',
label: $t('abp.meters.meterName'), label: $t('abp.CTWingManagement.CTWingAccountId'),
disabled: true,
},
{
component: 'Input',
fieldName: 'accountName',
label: $t('abp.CTWingManagement.AccountName'),
rules: z.string().min(1, { rules: z.string().min(1, {
message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.meters.meterName')}`, message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.CTWingManagement.AccountName')}`,
}), }),
}, },
{ {
component: 'Input', component: 'Input',
fieldName: 'meterAddress', fieldName: 'accountAccesskey',
label: $t('abp.meters.meterAddress'), label: $t('abp.CTWingManagement.AccountAccesskey'),
rules: z.string().min(1, {
message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.CTWingManagement.AccountAccesskey')}`,
}),
},
{
component: 'Input',
fieldName: 'phoneNumber',
label: $t('abp.CTWingManagement.PhoneNumber'),
rules: z rules: z
.string() .string()
.min(1, { .min(1, {
message: `${$t('common.pleaseInput')}${$t('common.numberType')}${$t('abp.meters.meterAddress')}`, message: `${$t('common.pleaseInput')}${$t('abp.CTWingManagement.PhoneNumber')}`,
}) })
.refine((value) => /^\d+$/.test(value), { .refine((value) => /^1[3-9]\d{9}$/.test(value), {
message: $t('abp.meters.checkmeterAddress'), message: $t('common.PhoneNumberFormatError'),
}), }),
}, },
{
component: 'Select',
componentProps: {
allowClear: true,
options: meterTypeOptions,
placeholder: `${$t('common.pleaseSelect')}${$t('abp.meters.meterType')}`,
},
fieldName: 'meterType',
label: $t('abp.meters.meterType'),
rules: z
.number()
.min(1, {
message: `${$t('common.pleaseSelect')}${$t('abp.meters.meterType')}`,
})
.default(1),
},
{
component: 'Select',
componentProps: {
allowClear: true,
options: rateOptions,
placeholder: `${$t('common.pleaseSelect')}${$t('abp.meters.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.meters.singleRate'),
},
{
component: 'Switch',
componentProps: {
class: 'w-auto',
},
fieldName: 'selfDevelop',
label: $t('abp.meters.selfDevelop'),
},
{
component: 'Input',
fieldName: 'brandType',
label: $t('abp.meters.brandType'),
rules: z.string().optional(),
},
{
component: 'Switch',
componentProps: {
class: 'w-auto',
},
fieldName: 'dynamicPassword',
label: $t('abp.meters.dynamicPassword'),
},
{
component: 'Input',
fieldName: 'password',
label: $t('abp.meters.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.meters.haveValve'),
},
{
component: 'Input',
fieldName: 'timesA',
label: $t('abp.meters.timesA'),
componentProps: {
allowClear: true,
placeholder: `${$t('common.pleaseInput')}${$t('abp.meters.timesA')}`,
},
dependencies: {
show(values: any) {
return values.meterType === 1;
},
triggerFields: ['meterType'],
},
rules: z
.string({
message: `${$t('common.pleaseInput')}${$t('abp.meters.timesA')}`,
})
.default('1'),
},
{
component: 'Input',
fieldName: 'timev',
label: $t('abp.meters.timev'),
componentProps: {
allowClear: true,
placeholder: `${$t('common.pleaseInput')}${$t('abp.meters.timev')}`,
},
dependencies: {
show(values: any) {
return values.meterType === 1;
},
triggerFields: ['meterType'],
},
rules: z
.string({
message: `${$t('common.pleaseInput')}${$t('abp.meters.timev')}`,
})
.default('1'),
},
{
component: 'Input',
fieldName: 'meteringCode',
label: $t('abp.meters.meteringCode'),
componentProps: {
allowClear: true,
placeholder: `${$t('common.pleaseInput')}${$t('abp.meters.meteringCode')}`,
},
rules: z
.string({
message: `${$t('common.pleaseInput')}${$t('abp.meters.meteringCode')}`,
})
.min(1, {
message: `${$t('common.MustGreaterTthan0')}`,
})
.default('1'),
},
]); ]);

View File

@ -2,35 +2,37 @@
import type { VbenFormProps } from '#/adapter/form'; import type { VbenFormProps } from '#/adapter/form';
import type { VxeGridProps } from '#/adapter/vxe-table'; import type { VxeGridProps } from '#/adapter/vxe-table';
import { h, ref } from 'vue'; import { h, nextTick, 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 { message as Message, Modal, Tag } from 'ant-design-vue'; import { message as Message, Tag } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form'; import { useVbenForm } from '#/adapter/form';
import { useVbenVxeGrid } from '#/adapter/vxe-table'; import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { import {
postDeviceInfoPage, postFilesDownload,
postAggregationDeviceDeleteAsync, postFilesUpload,
postDeviceInfoPage, postCtWingProductDeleteAsync,
postAggregationDeviceCreateAsync, postCtWingProductInsertAsync,
postCtWingProductListAsync,
postCtWingProductModifyAsync,
postCtWingProductProductStatusChangeAsync,
} from '#/api-client'; } from '#/api-client';
import { TableAction } from '#/components/table-action'; import { TableAction } from '#/components/table-action';
import { $t } from '#/locales'; import { $t } from '#/locales';
import { import {
addUserFormSchema, addProductFormSchema,
editUserFormSchemaEdit, editProductFormSchemaEdit,
meterTypeOptions,
querySchema, querySchema,
rateOptions, setFileSelectedCallback,
tableSchema, tableSchema,
} from './schema'; } from './schema';
defineOptions({ defineOptions({
name: 'AbpUser', name: 'CTWingProduct',
}); });
const router = useRouter(); const router = useRouter();
@ -55,7 +57,7 @@ const gridOptions: VxeGridProps<any> = {
proxyConfig: { proxyConfig: {
ajax: { ajax: {
query: async ({ page }, formValues) => { query: async ({ page }, formValues) => {
const { data } = await postDeviceInfoPage({ const { data } = await postCtWingProductListAsync({
body: { body: {
pageIndex: page.currentPage, pageIndex: page.currentPage,
pageSize: page.pageSize, pageSize: page.pageSize,
@ -71,13 +73,41 @@ const gridOptions: VxeGridProps<any> = {
const [Grid, gridApi] = useVbenVxeGrid({ formOptions, gridOptions }); const [Grid, gridApi] = useVbenVxeGrid({ formOptions, gridOptions });
const editRow: Record<string, any> = ref({}); const editRow: Record<string, any> = ref({});
//
let selectedFile: File | null = null;
//
setFileSelectedCallback((file) => {
selectedFile = file;
});
const [UserModal, userModalApi] = useVbenModal({ const [UserModal, userModalApi] = useVbenModal({
draggable: true, draggable: true,
footer: true,
showCancelButton: true,
showConfirmButton: true,
onConfirm: submit, onConfirm: submit,
onBeforeClose: () => { onBeforeClose: () => {
editRow.value = {}; //
return true; return true;
}, },
onOpen: () => {
//
selectedFile = null;
},
onOpenChange: (isOpen: boolean) => {
if (isOpen && editRow.value.id) {
//
nextTick(() => {
editFormApi.setValues({ ...editRow.value });
});
}
},
onCancel: () => {
//
selectedFile = null;
//
userModalApi.close();
},
}); });
const [AddForm, addFormApi] = useVbenForm({ const [AddForm, addFormApi] = useVbenForm({
@ -91,7 +121,7 @@ const [AddForm, addFormApi] = useVbenForm({
}, },
}, },
layout: 'horizontal', layout: 'horizontal',
schema: addUserFormSchema.value, schema: addProductFormSchema.value,
showCollapseButton: false, showCollapseButton: false,
showDefaultActions: false, showDefaultActions: false,
wrapperClass: 'grid-cols-2', wrapperClass: 'grid-cols-2',
@ -109,7 +139,7 @@ const [EditForm, editFormApi] = useVbenForm({
}, },
// //
layout: 'horizontal', layout: 'horizontal',
schema: editUserFormSchemaEdit.value, schema: editProductFormSchemaEdit.value,
showCollapseButton: false, showCollapseButton: false,
showDefaultActions: false, showDefaultActions: false,
wrapperClass: 'grid-cols-2', wrapperClass: 'grid-cols-2',
@ -119,31 +149,69 @@ 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 = isEdit
const api = postAggregationDeviceCreateAsync; ? postCtWingProductModifyAsync
: postCtWingProductInsertAsync;
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();
//
if (!formValues.deviceThingModelFileName) {
Message.error('请选择设备模型文件');
return;
}
//
if (selectedFile) {
try {
userModalApi.setState({ loading: true, confirmLoading: true });
const result = await postFilesUpload({ body: { files: [selectedFile] } });
if (result.status === 204 || result.status === 200) {
const fileInfo = result.data?.[0];
if (fileInfo && fileInfo.id) {
formValues.deviceThingModelFileId = fileInfo.id;
//
} else {
Message.error('文件上传成功但未获取到文件ID');
userModalApi.setState({ loading: false, confirmLoading: false });
return;
}
} else {
Message.error('文件上传失败');
userModalApi.setState({ loading: false, confirmLoading: false });
return;
}
} catch {
Message.error('文件上传失败');
userModalApi.setState({ loading: false, confirmLoading: false });
return;
}
}
//
selectedFile = null;
//
const fetchParams: any = isEdit 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 });
const resp = await api({ body: fetchParams }); const resp = await api({ body: fetchParams });
if (resp.data) { if (resp.data) {
Message.success( Message.success(
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(
@ -158,47 +226,91 @@ async function submit() {
async function onEdit(record: any) { async function onEdit(record: any) {
editRow.value = record; editRow.value = record;
userModalApi.open(); userModalApi.open();
editFormApi.setValues({ ...record }); //
selectedFile = null;
} }
function onDel(row: any) {
Modal.confirm({
title: `${$t('common.confirmDelete')}${row.meterName} ?`,
onOk: async () => {
const result = await postAggregationDeviceDeleteAsync({ body: { id: row.id } });
if (result) {
gridApi.reload();
Message.success($t('common.deleteSuccess'));
} else {
Message.error($t('common.deleteFail'));
}
},
});
}
const toStatusData = (row: Record<string, any>) => {
// 使
router.push({
path: '/iotdb/point',
query: {
DeviceType: row.meterType,
DeviceId: row.meterId,
FocusAddress: row.focusAddress,
},
});
};
const openAddModal = async () => { const openAddModal = async () => {
editRow.value = {}; editRow.value = {};
userModalApi.open(); userModalApi.open();
//
selectedFile = null;
}; };
//
async function onDel(record: any) {
try {
const resp = await postCtWingProductDeleteAsync({
body: { id: record.id },
});
if (resp.data) {
Message.success($t('common.deleteSuccess'));
//
selectedFile = null;
gridApi.reload();
} else {
Message.error($t('common.deleteFail'));
}
} catch {
Message.error($t('common.deleteFail'));
}
}
//
async function onDownloadFile(record: any) {
if (!record.deviceThingModelFileId) {
Message.error('文件ID不存在无法下载');
return;
}
try {
const { data } = await postFilesDownload({
body: { id: record.deviceThingModelFileId },
responseType: 'blob',
});
const url = window.URL.createObjectURL(new Blob([data as Blob]));
const link = document.createElement('a');
link.href = url;
link.setAttribute(
'download',
record.deviceThingModelFileName || 'device-model-file',
);
document.body.append(link);
link.click();
link.remove();
window.URL.revokeObjectURL(url);
Message.success('文件下载成功');
} catch {
Message.error('文件下载失败');
}
}
//
async function onStatusChange(record: any) {
try {
const resp = await postCtWingProductProductStatusChangeAsync({
body: {
id: record.id,
enabled: !record.isEnabled,
},
});
if (resp.data) {
Message.success(record.isEnabled ? '禁用成功' : '启用成功');
gridApi.reload();
} else {
Message.error(record.isEnabled ? '禁用失败' : '启用失败');
}
} catch {
Message.error(record.isEnabled ? '禁用失败' : '启用失败');
}
}
</script> </script>
<template> <template>
<Page auto-content-height> <Page auto-content-height>
<Grid> <Grid>
<template #toolbar-actions> <template #toolbar-actions>
<TableAction <TableAction :actions="[
:actions="[
{ {
label: $t('common.add'), label: $t('common.add'),
type: 'primary', type: 'primary',
@ -206,64 +318,26 @@ const openAddModal = async () => {
onClick: openAddModal.bind(null), onClick: openAddModal.bind(null),
auth: ['AbpIdentity.Users.Create'], auth: ['AbpIdentity.Users.Create'],
}, },
]" ]" />
/>
</template> </template>
<template #isMeterType="{ row }">
{{ meterTypeOptions[row.meterType - 1]?.label }}
</template>
<template #isSingleRate="{ row }">
{{ rateOptions.find((item) => item.value === row.singleRate)?.label }}
</template>
<template #isArchiveStatus="{ row }">
{{
row.archiveStatus ? $t('common.Issued') : $t('common.Undistributed')
}}
</template>
<template #isTripState="{ row }">
{{ row.tripState ? $t('common.SwitchOff') : $t('common.Closing') }}
</template>
<template #isHaveValve="{ row }">
<component
:is="
h(Tag, { color: row.haveValve ? 'green' : 'red' }, () =>
row.haveValve ? $t('common.yes') : $t('common.no'),
)
"
/>
</template>
<template #isSelfDevelop="{ row }">
<component
:is="
h(Tag, { color: row.selfDevelop ? 'green' : 'red' }, () =>
row.selfDevelop ? $t('common.yes') : $t('common.no'),
)
"
/>
</template>
<template #isDynamicPassword="{ row }">
<component
:is="
h(Tag, { color: row.dynamicPassword ? 'green' : 'red' }, () =>
row.dynamicPassword ? $t('common.yes') : $t('common.no'),
)
"
/>
</template>
<template #isEnable="{ row }"> <template #isEnable="{ row }">
<component <component :is="h(Tag, { color: row.isEnabled ? 'green' : 'red' }, () =>
:is=" row.isEnabled ? $t('common.yes') : $t('common.no'),
h(Tag, { color: row.enabled ? 'green' : 'red' }, () =>
row.enabled ? $t('common.yes') : $t('common.no'),
) )
" " />
/> </template>
<template #deviceThingModelFileName="{ row }">
<a v-if="row.deviceThingModelFileName && row.deviceThingModelFileId" @click="onDownloadFile(row)"
style="color: #1890ff; text-decoration: underline; cursor: pointer">
{{ row.deviceThingModelFileName }}
</a>
<span v-else>{{ row.deviceThingModelFileName || '-' }}</span>
</template> </template>
<template #action="{ row }"> <template #action="{ row }">
<TableAction <TableAction :actions="[
:actions="[
{ {
label: $t('common.edit'), label: $t('common.edit'),
type: 'link', type: 'link',
@ -271,8 +345,18 @@ const openAddModal = async () => {
auth: ['AbpIdentity.Users.Update'], auth: ['AbpIdentity.Users.Update'],
onClick: onEdit.bind(null, row), onClick: onEdit.bind(null, row),
}, },
]" {
:drop-down-actions="[ label: row.isEnabled ? '禁用' : '启用',
type: 'link',
danger: row.isEnabled,
size: 'small',
auth: ['AbpIdentity.Users.Update'],
popConfirm: {
title: `确定要${row.isEnabled ? '禁用' : '启用'}该产品吗?`,
confirm: onStatusChange.bind(null, row),
},
},
]" :drop-down-actions="[
{ {
label: $t('common.delete'), label: $t('common.delete'),
icon: 'ant-design:delete-outlined', icon: 'ant-design:delete-outlined',
@ -283,28 +367,10 @@ const openAddModal = async () => {
confirm: onDel.bind(null, row), confirm: onDel.bind(null, row),
}, },
}, },
{ ]" />
label: $t('abp.meters.pointData'),
icon: 'ant-design:profile-outlined',
type: 'primary',
auth: ['AbpIdentity.Users.Delete'],
onClick: toStatusData.bind(null, row),
},
{
label: $t('abp.meters.archivesIssued'),
icon: 'ant-design:cloud-download-outlined',
type: 'primary',
auth: ['AbpIdentity.Users.Delete'],
onClick: archivesIssued.bind(null, row),
},
]"
/>
</template> </template>
</Grid> </Grid>
<UserModal <UserModal :title="editRow.id ? $t('common.edit') : $t('common.add')" class="w-[800px]">
:title="editRow.id ? $t('common.edit') : $t('common.add')"
class="w-[800px]"
>
<component :is="editRow.id ? EditForm : AddForm" /> <component :is="editRow.id ? EditForm : AddForm" />
</UserModal> </UserModal>
</Page> </Page>

View File

@ -1,114 +1,136 @@
import type { VxeGridProps } from '#/adapter/vxe-table'; import type { VxeGridProps } from '#/adapter/vxe-table';
import { computed } from 'vue'; import { computed, h } from 'vue';
import { z } from '@vben/common-ui'; import { z } from '@vben/common-ui';
import { postCtWingAccountListAsync } from '#/api-client';
import { $t } from '#/locales'; import { $t } from '#/locales';
export const querySchema = computed(() => [ export const querySchema = computed(() => [
{ {
component: 'Input', component: 'Input',
fieldName: 'meterAddress', fieldName: 'productName',
label: $t('abp.meters.meterAddress'), label: $t('abp.CTWingManagement.ProductName'),
}, },
]); ]);
export const meterTypeOptions = [
{
label: $t('abp.meters.ElectricityMeter'),
value: 1,
},
{
label: $t('abp.meters.waterMeter'),
value: 2,
},
{
label: $t('abp.meters.GasMeter'),
value: 3,
},
{
label: $t('abp.meters.HeatMeter'),
value: 4,
},
{
label: $t('abp.meters.WaterMeterFlowmeter'),
value: 5,
},
{
label: $t('abp.meters.GasMeterFlowmeter'),
value: 6,
},
];
export const rateOptions = [
{
label: $t('abp.meters.MultipleRate'),
value: false,
},
{
label: $t('abp.meters.SingleRate'),
value: true,
},
];
export const tableSchema: any = computed((): VxeGridProps['columns'] => [ export const tableSchema: any = computed((): VxeGridProps['columns'] => [
{ title: $t('common.seq'), type: 'seq', width: 50 }, { title: $t('common.seq'), type: 'seq', width: 50 },
{ field: 'meterName', title: $t('abp.meters.meterName'), minWidth: '150' },
{ {
field: 'meterAddress', field: 'ctWingAccountName',
title: $t('abp.meters.meterAddress'), title: $t('abp.CTWingManagement.BelongingAccountName'),
minWidth: '150', minWidth: '150',
}, },
{ {
field: 'meterType', field: 'ioTPlatformProductId',
title: $t('abp.meters.meterType'), title: $t('abp.CTWingManagement.CTWingProductId'),
minWidth: '150', minWidth: '150',
slots: { default: 'isMeterType' },
}, },
{ {
field: 'dynamicPassword', field: 'productName',
title: $t('abp.meters.dynamicPassword'), title: $t('abp.CTWingManagement.ProductName'),
minWidth: '150', minWidth: '150',
slots: { default: 'isDynamicPassword' },
}, },
{ {
field: 'password', field: 'productAccesskey',
title: $t('abp.meters.password'), title: $t('abp.CTWingManagement.ProductAccesskey'),
minWidth: '100',
},
{
field: 'singleRate',
title: $t('abp.meters.singleRate'),
minWidth: '150', minWidth: '150',
slots: { default: 'isSingleRate' },
}, },
{ {
field: 'selfDevelop', field: 'communicationAddress',
title: $t('abp.meters.selfDevelop'), title: $t('abp.CTWingManagement.CommunicationAddress'),
minWidth: '150', minWidth: '150',
slots: { default: 'isSelfDevelop' },
}, },
{ field: 'brandType', title: $t('abp.meters.brandType'), minWidth: '150' },
{ {
field: 'archiveStatus', field: 'communicationAddressTLS',
title: $t('abp.meters.archiveStatus'), title: $t('abp.CTWingManagement.CommunicationAddressTLS'),
minWidth: '150', minWidth: '150',
slots: { default: 'isArchiveStatus' },
}, },
{ {
field: 'tripState', field: 'deviceThingModelFileName',
title: $t('abp.meters.tripState'), title: $t('abp.CTWingManagement.DeviceThingModelFileName'),
minWidth: '150', minWidth: '150',
slots: { default: 'isTripState' }, slots: { default: 'deviceThingModelFileName' },
}, },
{ field: 'timesA', title: $t('abp.meters.timesA'), minWidth: '100' },
{ field: 'timev', title: $t('abp.meters.timev'), minWidth: '100' },
{ {
field: 'haveValve', field: 'productCreateTime',
title: $t('abp.meters.haveValve'), title: $t('abp.CTWingManagement.IoTPlatformProductCreateTime'),
minWidth: '150', minWidth: '150',
slots: { default: 'isHaveValve' }, formatter: ({ cellValue }: any) => {
if (!cellValue) return '-';
const date = new Date(cellValue);
if (isNaN(date.getTime())) return '-';
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
}).replace(/\//g, '-');
},
}, },
{ {
field: 'enabled', field: 'productUpdateTime',
title: $t('abp.CTWingManagement.IoTPlatformProductUpdateTime'),
minWidth: '150',
formatter: ({ cellValue }: any) => {
if (!cellValue) return '-';
const date = new Date(cellValue);
if (isNaN(date.getTime())) return '-';
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
}).replace(/\//g, '-');
},
},
{
field: 'creationTime',
title: $t('abp.CTWingManagement.CreationTime'),
minWidth: '150',
formatter: ({ cellValue }: any) => {
if (!cellValue) return '-';
const date = new Date(cellValue);
if (isNaN(date.getTime())) return '-';
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
}).replace(/\//g, '-');
},
},
{
field: 'lastModificationTime',
title: $t('abp.CTWingManagement.LastModificationTime'),
minWidth: '150',
formatter: ({ cellValue }: any) => {
if (!cellValue) return '-';
const date = new Date(cellValue);
if (isNaN(date.getTime())) return '-';
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
}).replace(/\//g, '-');
},
},
{
field: 'isEnabled',
title: $t('common.isEnable'), title: $t('common.isEnable'),
minWidth: '150', minWidth: '150',
slots: { default: 'isEnable' }, slots: { default: 'isEnable' },
@ -117,326 +139,318 @@ export const tableSchema: any = computed((): VxeGridProps['columns'] => [
title: $t('common.action'), title: $t('common.action'),
field: 'action', field: 'action',
fixed: 'right', fixed: 'right',
width: '150', width: '200',
slots: { default: 'action' }, slots: { default: 'action' },
}, },
]); ]);
export const addUserFormSchema: any = computed(() => [ // 全局变量存储选择的文件
export let selectedFile: File | null = null;
// 文件选择回调函数
let _onFileSelected: ((file: File) => void) | null = null;
export function setFileSelectedCallback(callback: (file: File) => void) {
_onFileSelected = callback;
}
export const addProductFormSchema: any = computed(() => [
{ {
component: 'Input', component: 'ApiSelect',
fieldName: 'meterName', fieldName: 'ctWingAccountId',
label: $t('abp.meters.meterName'), label: $t('abp.CTWingManagement.BelongingAccountName'),
rules: z.string().min(1, {
message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.meters.meterName')}`,
}),
},
{
component: 'Input',
fieldName: 'meterAddress',
label: $t('abp.meters.meterAddress'),
rules: z
.string()
.min(1, {
message: `${$t('common.pleaseInput')}${$t('common.numberType')}${$t('abp.meters.meterAddress')}`,
})
.refine((value) => /^\d+$/.test(value), {
message: $t('abp.meters.checkmeterAddress'),
}),
},
{
component: 'Select',
componentProps: { componentProps: {
allowClear: true, api: postCtWingAccountListAsync,
options: meterTypeOptions, params: {
placeholder: `${$t('common.pleaseSelect')}${$t('abp.meters.meterType')}`, body: {
pageIndex: 1,
pageSize: 1000,
}, },
fieldName: 'meterType',
label: $t('abp.meters.meterType'),
rules: z
.number()
.min(1, {
message: `${$t('common.pleaseSelect')}${$t('abp.meters.meterType')}`,
})
.default(1),
}, },
{ labelField: 'accountName',
component: 'Select', valueField: 'ctWingAccountId',
componentProps: { immediate: true,
allowClear: true, afterFetch: (res: any) => {
options: rateOptions, // 如果是 Axios 响应对象,提取 data
placeholder: `${$t('common.pleaseSelect')}${$t('abp.meters.singleRate')}`, if (res && res.data) {
}, const data = res.data;
dependencies: {
show(values: any) { // 确保返回的是数组格式
return values.meterType === 1; if (Array.isArray(data)) {
}, return data;
rules(values: any) {
if (values.meterType === 1) {
return 'required';
} }
return null; // 如果是包装在 items 中的,提取出来
if (data && Array.isArray(data.items)) {
return data.items;
}
// 如果是包装在 data 中的,提取出来
if (data && Array.isArray(data.data)) {
return data.data;
}
}
// 如果都不是,返回空数组
return [];
}, },
triggerFields: ['meterType'], placeholder: `${$t('common.pleaseSelect')}${$t('abp.CTWingManagement.BelongingAccountName')}`,
}, },
fieldName: 'singleRate', rules: z.string().min(1, {
label: $t('abp.meters.singleRate'), message: `${$t('common.pleaseSelect')}${$t('abp.CTWingManagement.BelongingAccountName')}`,
}, }),
{
component: 'Switch',
componentProps: {
class: 'w-auto',
},
fieldName: 'selfDevelop',
label: $t('abp.meters.selfDevelop'),
}, },
{ {
component: 'Input', component: 'Input',
fieldName: 'brandType', fieldName: 'ioTPlatformProductId',
label: $t('abp.meters.brandType'), label: $t('abp.CTWingManagement.CTWingProductId'),
rules: z.string().optional(), rules: z.string().min(1, {
}, message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.CTWingManagement.CTWingProductId')}`,
{ }),
component: 'Switch',
componentProps: {
class: 'w-auto',
},
fieldName: 'dynamicPassword',
label: $t('abp.meters.dynamicPassword'),
}, },
{ {
component: 'Input', component: 'Input',
fieldName: 'password', fieldName: 'productAccesskey',
label: $t('abp.meters.password'), label: $t('abp.CTWingManagement.ProductAccesskey'),
rules: z.string().optional(), rules: z.string().min(1, {
}, message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.CTWingManagement.ProductAccesskey')}`,
{ }),
component: 'Switch',
componentProps: {
class: 'w-auto',
},
dependencies: {
show(values: any) {
return values.meterType === 2;
},
triggerFields: ['meterType'],
},
fieldName: 'haveValve',
label: $t('abp.meters.haveValve'),
}, },
{ {
component: 'Input', component: 'Input',
fieldName: 'timesA', fieldName: 'communicationAddress',
label: $t('abp.meters.timesA'), label: $t('abp.CTWingManagement.CommunicationAddress'),
componentProps: { rules: z.string().min(1, {
allowClear: true, message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.CTWingManagement.CommunicationAddress')}`,
placeholder: `${$t('common.pleaseInput')}${$t('abp.meters.timesA')}`, }),
},
dependencies: {
show(values: any) {
return values.meterType === 1;
},
triggerFields: ['meterType'],
},
rules: z
.string({
message: `${$t('common.pleaseInput')}${$t('abp.meters.timesA')}`,
})
.default('1'),
}, },
{ {
component: 'Input', component: 'Input',
fieldName: 'timev', fieldName: 'communicationAddressTLS',
label: $t('abp.meters.timev'), label: $t('abp.CTWingManagement.CommunicationAddressTLS'),
componentProps: { rules: z.string().min(1, {
allowClear: true, message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.CTWingManagement.CommunicationAddressTLS')}`,
placeholder: `${$t('common.pleaseInput')}${$t('abp.meters.timev')}`, }),
},
dependencies: {
show(values: any) {
return values.meterType === 1;
},
triggerFields: ['meterType'],
},
rules: z
.string({
message: `${$t('common.pleaseInput')}${$t('abp.meters.timesA')}`,
})
.default('1'),
}, },
{ {
component: 'Input', component: 'Input',
fieldName: 'meteringCode', fieldName: 'deviceThingModelFileName',
label: $t('abp.meters.meteringCode'), label: $t('abp.CTWingManagement.DeviceThingModelFileName'),
componentProps: { componentProps: {
allowClear: true, placeholder: '请选择文件',
placeholder: `${$t('common.pleaseInput')}${$t('abp.meters.meteringCode')}`, readonly: true,
addonAfter: h(
'button',
{
type: 'button',
style:
'border: none; background: #1890ff; color: white; padding: 4px 8px; border-radius: 4px; cursor: pointer;',
onClick: () => {
const input = document.createElement('input');
input.type = 'file';
input.accept = '.json,.xlsx,.xls';
input.addEventListener('change', (e: any) => {
const file = e.target.files[0];
if (file) {
// 只显示文件名,不上传
const currentInput = document.querySelector(
'input[placeholder="请选择文件"]',
) as HTMLInputElement;
if (currentInput) {
currentInput.value = file.name;
// 触发change事件
currentInput.dispatchEvent(
new Event('input', { bubbles: true }),
);
currentInput.dispatchEvent(
new Event('change', { bubbles: true }),
);
// 存储文件对象到全局变量,用于后续上传
selectedFile = file;
// 调用回调函数
if (_onFileSelected) {
_onFileSelected(file);
}
}
console.log(
'文件已选择:',
file.name,
'大小:',
file.size,
'字节',
);
}
});
input.click();
},
},
'选择文件',
),
},
rules: z.string().min(1, {
message: `${$t('common.pleaseSelect')}${$t('abp.CTWingManagement.DeviceThingModelFileName')}`,
}),
},
{
component: 'Input',
fieldName: 'deviceThingModelFileId',
label: '',
componentProps: {
type: 'hidden',
}, },
rules: z
.string({
message: `${$t('common.pleaseInput')}${$t('abp.meters.meteringCode')}`,
})
.default('1'),
}, },
]); ]);
export const editUserFormSchemaEdit: any = computed(() => [ export const editProductFormSchemaEdit: any = computed(() => [
{ {
component: 'Input', component: 'ApiSelect',
fieldName: 'meterName', fieldName: 'ctWingAccountId',
label: $t('abp.meters.meterName'), label: $t('abp.CTWingManagement.BelongingAccountName'),
rules: z.string().min(1, {
message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.meters.meterName')}`,
}),
},
{
component: 'Input',
fieldName: 'meterAddress',
label: $t('abp.meters.meterAddress'),
rules: z
.string()
.min(1, {
message: `${$t('common.pleaseInput')}${$t('common.numberType')}${$t('abp.meters.meterAddress')}`,
})
.refine((value) => /^\d+$/.test(value), {
message: $t('abp.meters.checkmeterAddress'),
}),
},
{
component: 'Select',
componentProps: { componentProps: {
allowClear: true, api: postCtWingAccountListAsync,
options: meterTypeOptions, params: {
placeholder: `${$t('common.pleaseSelect')}${$t('abp.meters.meterType')}`, body: {
pageIndex: 1,
pageSize: 1000,
}, },
fieldName: 'meterType',
label: $t('abp.meters.meterType'),
rules: z
.number()
.min(1, {
message: `${$t('common.pleaseSelect')}${$t('abp.meters.meterType')}`,
})
.default(1),
}, },
{ labelField: 'accountName',
component: 'Select', valueField: 'ctWingAccountId',
componentProps: { immediate: true,
allowClear: true, disabled: true, // 编辑时禁用
options: rateOptions, afterFetch: (res: any) => {
placeholder: `${$t('common.pleaseSelect')}${$t('abp.meters.singleRate')}`, // 如果是 Axios 响应对象,提取 data
}, if (res && res.data) {
dependencies: { const data = res.data;
show(values: any) {
return values.meterType === 1; // 确保返回的是数组格式
}, if (Array.isArray(data)) {
rules(values: any) { return data;
if (values.meterType === 1) {
return 'required';
} }
return null; // 如果是包装在 items 中的,提取出来
if (data && Array.isArray(data.items)) {
return data.items;
}
// 如果是包装在 data 中的,提取出来
if (data && Array.isArray(data.data)) {
return data.data;
}
}
// 如果都不是,返回空数组
return [];
}, },
triggerFields: ['meterType'], placeholder: `${$t('common.pleaseSelect')}${$t('abp.CTWingManagement.BelongingAccountName')}`,
}, },
fieldName: 'singleRate', rules: z.string().min(1, {
label: $t('abp.meters.singleRate'), message: `${$t('common.pleaseSelect')}${$t('abp.CTWingManagement.BelongingAccountName')}`,
}, }),
{
component: 'Switch',
componentProps: {
class: 'w-auto',
},
fieldName: 'selfDevelop',
label: $t('abp.meters.selfDevelop'),
}, },
{ {
component: 'Input', component: 'Input',
fieldName: 'brandType', fieldName: 'ioTPlatformProductId',
label: $t('abp.meters.brandType'), label: $t('abp.CTWingManagement.CTWingProductId'),
rules: z.string().optional(), disabled: true,
},
{
component: 'Switch',
componentProps: { componentProps: {
class: 'w-auto', readonly: true, // 编辑时只读
}, },
fieldName: 'dynamicPassword', rules: z.string().min(1, {
label: $t('abp.meters.dynamicPassword'), message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.CTWingManagement.CTWingProductId')}`,
}),
}, },
{ {
component: 'Input', component: 'Input',
fieldName: 'password', fieldName: 'productAccesskey',
label: $t('abp.meters.password'), label: $t('abp.CTWingManagement.ProductAccesskey'),
rules: z.string().optional(), disabled: true,
},
{
component: 'Switch',
componentProps: { componentProps: {
class: 'w-auto', readonly: true, // 编辑时只读
}, },
dependencies: { rules: z.string().min(1, {
show(values: any) { message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.CTWingManagement.ProductAccesskey')}`,
return values.meterType === 2; }),
},
triggerFields: ['meterType'],
},
fieldName: 'haveValve',
label: $t('abp.meters.haveValve'),
}, },
{ {
component: 'Input', component: 'Input',
fieldName: 'timesA', fieldName: 'communicationAddress',
label: $t('abp.meters.timesA'), label: $t('abp.CTWingManagement.CommunicationAddress'),
componentProps: { rules: z.string().min(1, {
allowClear: true, message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.CTWingManagement.CommunicationAddress')}`,
placeholder: `${$t('common.pleaseInput')}${$t('abp.meters.timesA')}`, }),
},
dependencies: {
show(values: any) {
return values.meterType === 1;
},
triggerFields: ['meterType'],
},
rules: z
.string({
message: `${$t('common.pleaseInput')}${$t('abp.meters.timesA')}`,
})
.default('1'),
}, },
{ {
component: 'Input', component: 'Input',
fieldName: 'timev', fieldName: 'communicationAddressTLS',
label: $t('abp.meters.timev'), label: $t('abp.CTWingManagement.CommunicationAddressTLS'),
componentProps: { rules: z.string().min(1, {
allowClear: true, message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.CTWingManagement.CommunicationAddressTLS')}`,
placeholder: `${$t('common.pleaseInput')}${$t('abp.meters.timev')}`, }),
},
dependencies: {
show(values: any) {
return values.meterType === 1;
},
triggerFields: ['meterType'],
},
rules: z
.string({
message: `${$t('common.pleaseInput')}${$t('abp.meters.timev')}`,
})
.default('1'),
}, },
{ {
component: 'Input', component: 'Input',
fieldName: 'meteringCode', fieldName: 'deviceThingModelFileName',
label: $t('abp.meters.meteringCode'), label: $t('abp.CTWingManagement.DeviceThingModelFileName'),
componentProps: { componentProps: {
allowClear: true, placeholder: '请选择文件',
placeholder: `${$t('common.pleaseInput')}${$t('abp.meters.meteringCode')}`, readonly: true,
addonAfter: h(
'button',
{
type: 'button',
style:
'border: none; background: #1890ff; color: white; padding: 4px 8px; border-radius: 4px; cursor: pointer;',
onClick: () => {
const input = document.createElement('input');
input.type = 'file';
input.accept = '.json,.xlsx,.xls';
input.addEventListener('change', (e: any) => {
const file = e.target.files[0];
if (file) {
// 只显示文件名,不上传
const currentInput = document.querySelector(
'input[placeholder="请选择文件"]',
) as HTMLInputElement;
if (currentInput) {
currentInput.value = file.name;
// 触发change事件
currentInput.dispatchEvent(
new Event('input', { bubbles: true }),
);
currentInput.dispatchEvent(
new Event('change', { bubbles: true }),
);
// 存储文件对象到全局变量,用于后续上传
selectedFile = file;
// 调用回调函数
if (_onFileSelected) {
_onFileSelected(file);
}
}
console.log(
'文件已选择:',
file.name,
'大小:',
file.size,
'字节',
);
}
});
input.click();
},
},
'选择文件',
),
},
rules: z.string().min(1, {
message: `${$t('common.pleaseSelect')}${$t('abp.CTWingManagement.DeviceThingModelFileName')}`,
}),
},
{
component: 'Input',
fieldName: 'deviceThingModelFileId',
label: '',
componentProps: {
type: 'hidden',
}, },
rules: z
.string({
message: `${$t('common.pleaseInput')}${$t('abp.meters.meteringCode')}`,
})
.min(1, {
message: `${$t('common.MustGreaterTthan0')}`,
})
.default('1'),
}, },
]); ]);