设备管理

This commit is contained in:
FLL 2025-07-16 17:30:18 +08:00
parent fa30efb031
commit 72ddc3d5f3
5 changed files with 228 additions and 103 deletions

View File

@ -26,6 +26,16 @@ export interface DeviceLocationVO {
*/
searchValue: string;
/**
*
*/
locationObjName: string;
/**
*
*/
remark: string;
}
export interface DeviceLocationForm extends BaseEntity {

View File

@ -1,5 +1,7 @@
import type { FormSchemaGetter } from '#/adapter/form';
import type { VxeGridProps } from '#/adapter/vxe-table';
import {getDictOptions} from "#/utils/dict";
import {renderDict} from "#/utils/render";
export const querySchema: FormSchemaGetter = () => [
@ -8,23 +10,14 @@ export const querySchema: FormSchemaGetter = () => [
fieldName: 'locationName',
label: '位置名称',
},
{
component: 'Input',
fieldName: 'locationCode',
label: '位置编号',
},
{
component: 'Select',
componentProps: {
options: getDictOptions('pro_location_type'),
},
fieldName: 'locationType',
label: '位置类型',
},
{
component: 'Input',
fieldName: 'searchValue',
label: '搜索值',
},
];
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
@ -32,24 +25,30 @@ export const querySchema: FormSchemaGetter = () => [
export const columns: VxeGridProps['columns'] = [
{ type: 'checkbox', width: 60 },
{
title: '主键',
field: 'id',
title: '位置编码',
field: 'locationCode',
},
{
title: '位置名称',
field: 'locationName',
},
{
title: '位置编号',
field: 'locationCode',
},
{
title: '位置类型',
field: 'locationType',
slots: {
default: ({ row }) => {
return renderDict(row.locationType, 'pro_location_type');
},
},
},
{
title: '搜索值',
field: 'searchValue',
title: '位置对象',
field: 'locationObject',
},
{
title: '备注',
field: 'remark',
},
{
field: 'action',
@ -60,37 +59,41 @@ export const columns: VxeGridProps['columns'] = [
},
];
export const modalSchema: FormSchemaGetter = () => [
{
label: '主键',
fieldName: 'id',
component: 'Input',
dependencies: {
show: () => false,
triggerFields: [''],
},
},
{
label: '位置名称',
fieldName: 'locationName',
component: 'Input',
rules: 'required',
},
{
label: '位置编号',
fieldName: 'locationCode',
component: 'Input',
},
{
label: '位置类型',
fieldName: 'locationType',
component: 'Select',
componentProps: {
},
},
{
label: '搜索值',
fieldName: 'searchValue',
component: 'Input',
},
];
// export const modalSchema: FormSchemaGetter = () => [
// {
// label: '主键',
// fieldName: 'id',
// component: 'Input',
// dependencies: {
// show: () => false,
// triggerFields: [''],
// },
// },
// {
// label: '位置名称',
// fieldName: 'locationName',
// component: 'Input',
// rules: 'required',
// },
// {
// label: '位置类型',
// fieldName: 'locationType',
// component: 'Select',
// componentProps: {
// options: getDictOptions('pro_location_type'),
// },
// rules: 'selectRequired',
// },
// {
// component: 'TreeSelect',
// fieldName: 'locationObject',
// defaultValue: undefined,
// label: '位置对象',
// rules: 'selectRequired',
// },
// {
// label: '备注',
// fieldName: 'remark',
// component: 'Textarea',
// },
// ];

View File

@ -0,0 +1,52 @@
<script setup lang="ts">
import type {DeviceLocationVO} from '#/api/property/equipmentManagement/deviceLocation/model';
import {shallowRef} from 'vue';
import {useVbenModal} from '@vben/common-ui';
import {Descriptions, DescriptionsItem} from 'ant-design-vue';
import {deviceLocationInfo} from '#/api/property/equipmentManagement/deviceLocation';
import {renderDict} from "#/utils/render";
const [BasicModal, modalApi] = useVbenModal({
onOpenChange: handleOpenChange,
onClosed() {
deviceLocationDetail.value = null;
},
});
const deviceLocationDetail = shallowRef<null | DeviceLocationVO>(null);
async function handleOpenChange(open: boolean) {
if (!open) {
return null;
}
modalApi.modalLoading(true);
const {id} = modalApi.getData() as { id: number | string };
const response = await deviceLocationInfo(id);
deviceLocationDetail.value = response;
modalApi.modalLoading(false);
}
</script>
<template>
<BasicModal :footer="false" :fullscreen-button="false" title="查看收费" class="w-[70%]">
<Descriptions v-if="deviceLocationDetail" size="small" :column="2" bordered :labelStyle="{width:'100px'}">
<DescriptionsItem label="位置编码">
{{ deviceLocationDetail.locationCode }}
</DescriptionsItem>
<DescriptionsItem label="位置名称">
{{ deviceLocationDetail.locationName }}
</DescriptionsItem>
<DescriptionsItem label="位置类型" v-if="deviceLocationDetail.locationType!=null">
<component
:is="renderDict(deviceLocationDetail.locationType,'pro_location_type')"
/>
</DescriptionsItem>
<DescriptionsItem label="位置对象">
{{ deviceLocationDetail.locationObjName }}
</DescriptionsItem>
<DescriptionsItem label="备注">
{{ deviceLocationDetail.remark }}
</DescriptionsItem>
</Descriptions>
</BasicModal>
</template>

View File

@ -1,23 +1,71 @@
<script setup lang="ts">
import { computed, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { cloneDeep } from '@vben/utils';
import { useVbenForm } from '#/adapter/form';
import { deviceLocationAdd, deviceLocationInfo, deviceLocationUpdate } from '#/api/property/deviceLocation';
import {cloneDeep, handleNode} from '@vben/utils';
import {useVbenForm} from '#/adapter/form';
import { deviceLocationAdd, deviceLocationInfo, deviceLocationUpdate } from '#/api/property/equipmentManagement/deviceLocation';
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
import { modalSchema } from './data';
// import { modalSchema } from './data';
import {communityTree} from "#/api/property/community";
import {getDictOptions} from "#/utils/dict";
const emit = defineEmits<{ reload: [] }>();
const isUpdate = ref(false);
const title = computed(() => {
return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
});
const modalSchema = [
{
label: '主键',
fieldName: 'id',
component: 'Input',
dependencies: {
show: () => false,
triggerFields: [''],
},
},
{
label: '位置名称',
fieldName: 'locationName',
component: 'Input',
rules: 'required',
},
{
label: '位置类型',
fieldName: 'locationType',
component: 'Select',
componentProps: {
options: getDictOptions('pro_location_type'),
onChange: async (value: string) => {
if(value) {
await setupCommunitySelect(value)
await formApi.setFieldValue('locationObjId', null);
}
}
},
rules: 'selectRequired',
},
{
component: 'TreeSelect',
fieldName: 'locationObjId',
defaultValue: undefined,
label: '位置对象',
dependencies: {
show: (formValue) =>formValue.locationType!==undefined ,
triggerFields: ['locationType'],
},
rules: 'selectRequired',
},
{
label: '备注',
fieldName: 'remark',
component: 'Textarea',
},
];
const [BasicForm, formApi] = useVbenForm({
commonConfig: {
//
@ -29,7 +77,7 @@ const [BasicForm, formApi] = useVbenForm({
class: 'w-full',
}
},
schema: modalSchema(),
schema: modalSchema,
showDefaultActions: false,
wrapperClass: 'grid-cols-2',
});
@ -53,16 +101,14 @@ const [BasicModal, modalApi] = useVbenModal({
return null;
}
modalApi.modalLoading(true);
const { id } = modalApi.getData() as { id?: number | string };
isUpdate.value = !!id;
if (isUpdate.value && id) {
const record = await deviceLocationInfo(id);
record.locationType = record.locationType?.toString();
await formApi.setValues(record);
}
await markInitialized();
modalApi.modalLoading(false);
},
});
@ -74,7 +120,6 @@ async function handleConfirm() {
if (!valid) {
return;
}
// getValuesreadonly
const data = cloneDeep(await formApi.getValues());
await (isUpdate.value ? deviceLocationUpdate(data) : deviceLocationAdd(data));
resetInitialized();
@ -91,6 +136,39 @@ async function handleClosed() {
await formApi.resetForm();
resetInitialized();
}
async function setupCommunitySelect(value:any) {
const areaList = await communityTree(Number(value)+1);
const splitStr = '/';
handleNode(areaList, 'label', splitStr, function (node: any) {
if (node.level != Number(value)+1) {
node.disabled = true;
}
});
formApi.updateSchema([
{
componentProps: () => ({
class: 'w-full',
fieldNames: {
key: 'id',
label: 'label',
value: 'code',
children: 'children',
},
placeholder: '请选择',
showSearch: true,
treeData: areaList,
treeDefaultExpandAll: true,
treeLine: { showLeafIcon: false },
//
treeNodeFilterProp: 'label',
//
treeNodeLabelProp: 'fullName',
}),
fieldName: 'locationObjId',
},
]);
}
</script>
<template>

View File

@ -1,29 +1,19 @@
<script setup lang="ts">
import type { Recordable } from '@vben/types';
import { ref } from 'vue';
import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
import { getVxePopupContainer } from '@vben/utils';
import { Modal, Popconfirm, Space } from 'ant-design-vue';
import dayjs from 'dayjs';
import {
import {
useVbenVxeGrid,
vxeCheckboxChecked,
type VxeGridProps
type VxeGridProps
} from '#/adapter/vxe-table';
import {
deviceLocationExport,
deviceLocationList,
deviceLocationRemove,
} from '#/api/property/deviceLocation';
import type { DeviceLocationForm } from '#/api/property/deviceLocation/model';
import { commonDownloadExcel } from '#/utils/file/download';
} from '#/api/property/equipmentManagement/deviceLocation';
import type { DeviceLocationForm } from '#/api/property/equipmentManagement/deviceLocation/model';
import deviceLocationModal from './deviceLocation-modal.vue';
import deviceLocationDetail from './deviceLocation-detail.vue';
import { columns, querySchema } from './data';
const formOptions: VbenFormProps = {
@ -35,15 +25,6 @@ const formOptions: VbenFormProps = {
},
schema: querySchema(),
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
// RangePicker /
//
// fieldMappingTime: [
// [
// 'createTime',
// ['params[beginTime]', 'params[endTime]'],
// ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
// ],
// ],
};
const gridOptions: VxeGridProps = {
@ -55,8 +36,6 @@ const gridOptions: VxeGridProps = {
//
// trigger: 'row',
},
// 使i18ngetter
// columns: columns(),
columns,
height: 'auto',
keepSource: true,
@ -117,10 +96,13 @@ function handleMultiDelete() {
});
}
function handleDownloadExcel() {
commonDownloadExcel(deviceLocationExport, '设备位置数据', tableApi.formApi.form.values, {
fieldMappingTime: formOptions.fieldMappingTime,
});
const [deviceLocationDetailModal, deviceLocationDetailApi] = useVbenModal({
connectedComponent: deviceLocationDetail,
});
async function handleInfo(row: Required<DeviceLocationForm>) {
deviceLocationDetailApi.setData({ id: row.id });
deviceLocationDetailApi.open();
}
</script>
@ -129,17 +111,11 @@ function handleDownloadExcel() {
<BasicTable table-title="设备位置列表">
<template #toolbar-tools>
<Space>
<a-button
v-access:code="['property:deviceLocation:export']"
@click="handleDownloadExcel"
>
{{ $t('pages.common.export') }}
</a-button>
<a-button
:disabled="!vxeCheckboxChecked(tableApi)"
danger
type="primary"
v-access:code="['property:deviceLocation:remove']"
type="primary"
v-access:code="['property:deviceLocation:remove']"
@click="handleMultiDelete">
{{ $t('pages.common.delete') }}
</a-button>
@ -154,6 +130,11 @@ function handleDownloadExcel() {
</template>
<template #action="{ row }">
<Space>
<ghost-button
@click.stop="handleInfo(row)"
>
{{ $t('pages.common.info') }}
</ghost-button>
<ghost-button
v-access:code="['property:deviceLocation:edit']"
@click.stop="handleEdit(row)"
@ -178,5 +159,6 @@ function handleDownloadExcel() {
</template>
</BasicTable>
<DeviceLocationModal @reload="tableApi.query()" />
<deviceLocationDetailModal/>
</Page>
</template>