Merge branch 'master' of http://47.109.37.87:3000/by2025/admin-vben5
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run

# Conflicts:
#	apps/web-antd/src/views/sis/accessControl/device/accessControlModal.vue
This commit is contained in:
lxj 2025-08-05 16:47:10 +08:00
commit febe532404
9 changed files with 215 additions and 195 deletions

View File

@ -21,6 +21,16 @@ export interface AuthGroupVO {
*/ */
isEnable: boolean; isEnable: boolean;
/**
* id
*/
acIds?: string[] | number[];
/**
* id
*/
floorIds?: string[] | number[];
} }
export interface AuthGroupForm extends BaseEntity { export interface AuthGroupForm extends BaseEntity {

View File

@ -1,177 +1,182 @@
import type { BaseEntity, PageQuery } from '#/api/common'; import type { BaseEntity, PageQuery } from '#/api/common'
export interface DeviceManageVO { export interface DeviceManageVO {
/** /**
* id * id
*/ */
id: string | number; id: string | number
/** /**
* *
*/ */
deviceNo: string; deviceNo: string
/** /**
* *
*/ */
deviceName: string; deviceName: string
/** /**
* ip * ip
*/ */
deviceIp: string; deviceIp: string
/** /**
* *
*/ */
devicePort: number; devicePort: number
/** /**
* *
*/ */
deviceAccount: string; deviceAccount: string
/** /**
* *
*/ */
devicePwd: string; devicePwd: string
/** /**
* *
*/ */
deviceMac: string; deviceMac: string
/** /**
* 线 0:离线 1:在线 2:未知 * 线 0:离线 1:在线 2:未知
*/ */
deviceStatus: number; deviceStatus: number
/** /**
* id * id
*/ */
parentId: string | number; parentId: string | number
/** /**
* *
*/ */
channelNo: string; channelNo: string
/** /**
* ip * ip
*/ */
vcrIp: string; vcrIp: string
/** /**
* *
*/ */
vcrPort: number; vcrPort: number
/** /**
* *
*/ */
vcrAccount: string; vcrAccount: string
/** /**
* *
*/ */
vcrPwd: string; vcrPwd: string
/** /**
* id * id
*/ */
accessControlId: string | number; accessControlId: string | number
/**
* id
*/
floorId: string | number
} }
export interface DeviceManageForm extends BaseEntity { export interface DeviceManageForm extends BaseEntity {
/** /**
* id * id
*/ */
id?: string | number; id?: string | number
/** /**
* *
*/ */
deviceNo?: string; deviceNo?: string
/** /**
* *
*/ */
deviceName?: string; deviceName?: string
/** /**
* ip * ip
*/ */
deviceIp?: string; deviceIp?: string
/** /**
* *
*/ */
devicePort?: number; devicePort?: number
/** /**
* *
*/ */
deviceAccount?: string; deviceAccount?: string
/** /**
* *
*/ */
devicePwd?: string; devicePwd?: string
/** /**
* *
*/ */
deviceMac?: string; deviceMac?: string
/** /**
* 线 0:离线 1:在线 2:未知 * 线 0:离线 1:在线 2:未知
*/ */
deviceStatus?: number; deviceStatus?: number
} }
export interface DeviceManageQuery extends PageQuery { export interface DeviceManageQuery extends PageQuery {
/** /**
* *
*/ */
deviceNo?: string; deviceNo?: string
/** /**
* *
*/ */
deviceName?: string; deviceName?: string
/** /**
* ip * ip
*/ */
deviceIp?: string; deviceIp?: string
/** /**
* *
*/ */
devicePort?: number; devicePort?: number
/** /**
* *
*/ */
deviceAccount?: string; deviceAccount?: string
/** /**
* *
*/ */
devicePwd?: string; devicePwd?: string
/** /**
* *
*/ */
deviceMac?: string; deviceMac?: string
/** /**
* 线 0:离线 1:在线 2:未知 * 线 0:离线 1:在线 2:未知
*/ */
deviceStatus?: number; deviceStatus?: number
/** /**
* *
*/ */
params?: any; params?: any
} }

View File

@ -59,22 +59,3 @@ export function elevatorInfoUpdate(data: ElevatorInfoForm) {
export function elevatorInfoRemove(elevatorId: ID | IDS) { export function elevatorInfoRemove(elevatorId: ID | IDS) {
return requestClient.deleteWithMsg<void>(`/sis/elevatorInfo/${elevatorId}`); return requestClient.deleteWithMsg<void>(`/sis/elevatorInfo/${elevatorId}`);
} }
/**
*
* @param params
* @returns void
*/
export function refAdd(data: ElevatorFloorRefForm) {
return requestClient.postWithMsg<void>('/sis/elevatorInfo/ref/add', data);
}
/**
*
* @param id
* @returns void
*/
export function refQuery(id: ID) {
return requestClient.get<ElevatorFloorRefVo[]>(`/sis/elevatorInfo/ref/${id}`);
}

View File

@ -1,11 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref } from 'vue'; import { computed, ref } from 'vue'
import { useVbenModal } from '@vben/common-ui'; import { useVbenModal } from '@vben/common-ui'
import { $t } from '@vben/locales'; import { $t } from '@vben/locales'
import { cloneDeep, getPopupContainer, handleNode } from '@vben/utils'; import { cloneDeep, getPopupContainer, handleNode } from '@vben/utils'
import { useVbenForm } from '#/adapter/form'; import { useVbenForm } from '#/adapter/form'
import { import {
accessControlAdd, accessControlAdd,
accessControlInfo, accessControlInfo,
@ -17,12 +17,12 @@ import { modalSchema } from './data';
import type {DeviceManageQuery} from "#/api/sis/deviceManage/model"; import type {DeviceManageQuery} from "#/api/sis/deviceManage/model";
import {deviceManageList} from "#/api/sis/deviceManage"; import {deviceManageList} from "#/api/sis/deviceManage";
const emit = defineEmits<{ reload: [] }>(); const emit = defineEmits<{ reload: [] }>()
const isUpdate = ref(false); const isUpdate = ref(false)
const title = computed(() => { const title = computed(() => {
return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add'); return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add')
}); })
const [BasicForm, formApi] = useVbenForm({ const [BasicForm, formApi] = useVbenForm({
commonConfig: { commonConfig: {
@ -38,14 +38,14 @@ const [BasicForm, formApi] = useVbenForm({
schema: modalSchema(), schema: modalSchema(),
showDefaultActions: false, showDefaultActions: false,
wrapperClass: 'grid-cols-1', wrapperClass: 'grid-cols-1',
}); })
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff( const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
{ {
initializedGetter: defaultFormValueGetter(formApi), initializedGetter: defaultFormValueGetter(formApi),
currentGetter: defaultFormValueGetter(formApi), currentGetter: defaultFormValueGetter(formApi),
}, },
); )
const [BasicModal, modalApi] = useVbenModal({ const [BasicModal, modalApi] = useVbenModal({
// //
@ -56,54 +56,53 @@ const [BasicModal, modalApi] = useVbenModal({
onConfirm: handleConfirm, onConfirm: handleConfirm,
onOpenChange: async (isOpen) => { onOpenChange: async (isOpen) => {
if (!isOpen) { if (!isOpen) {
return null; return null
} }
modalApi.modalLoading(true); modalApi.modalLoading(true)
setupCommunitySelect(); setupCommunitySelect()
const { id } = modalApi.getData() as { id?: number | string }; const { id } = modalApi.getData() as { id?: number | string }
isUpdate.value = !!id; isUpdate.value = !!id
if (isUpdate.value && id) { if (isUpdate.value && id) {
const record = await accessControlInfo(id); const record = await accessControlInfo(id)
await formApi.setValues(record); await formApi.setValues(record)
} }
await markInitialized(); await markInitialized()
modalApi.modalLoading(false); modalApi.modalLoading(false)
}, },
}); })
async function handleConfirm() { async function handleConfirm() {
try { try {
modalApi.lock(true); modalApi.lock(true)
const { valid } = await formApi.validate(); const { valid } = await formApi.validate()
if (!valid) { if (!valid) {
return; return
} }
// getValuesreadonly // getValuesreadonly
const data = cloneDeep(await formApi.getValues()); const data = cloneDeep(await formApi.getValues())
await (isUpdate.value ? accessControlUpdate(data) : accessControlAdd(data)); await (isUpdate.value ? accessControlUpdate(data) : accessControlAdd(data))
resetInitialized(); resetInitialized()
emit('reload'); emit('reload')
modalApi.close(); modalApi.close()
} catch (error) { } catch (error) {
console.error(error); console.error(error)
} finally { } finally {
modalApi.lock(false); modalApi.lock(false)
} }
} }
async function setupCommunitySelect() { async function setupCommunitySelect() {
const areaList = await communityTree(3); const areaList = await communityTree(3)
// / // /
// addFullName(areaList, 'areaName', ' / '); // addFullName(areaList, 'areaName', ' / ');
const splitStr = '/'; const splitStr = '/'
handleNode(areaList, 'label', splitStr, function (node: any) { handleNode(areaList, 'label', splitStr, function (node: any) {
if (node.level != 3) { if (node.level != 3) {
node.disabled = true; node.disabled = true
} }
}); })
// //
const params: DeviceManageQuery = { const params: DeviceManageQuery = {
pageNum: 1, pageNum: 1,
@ -119,7 +118,6 @@ async function setupCommunitySelect() {
deviceId: item.id, deviceId: item.id,
} }
}) })
formApi.updateSchema([ formApi.updateSchema([
{ {
componentProps: () => ({ componentProps: () => ({
@ -160,8 +158,8 @@ async function setupCommunitySelect() {
} }
async function handleClosed() { async function handleClosed() {
await formApi.resetForm(); await formApi.resetForm()
resetInitialized(); resetInitialized()
} }
</script> </script>

View File

@ -25,7 +25,6 @@ export const querySchema: FormSchemaGetter = () => [
api: async () => { api: async () => {
const areaList = await communityTree(3); const areaList = await communityTree(3);
addFullName(areaList, 'label', '/'); addFullName(areaList, 'label', '/');
console.log(areaList);
return areaList; return areaList;
}, },
}, },

View File

@ -1,26 +1,26 @@
<script setup lang="ts"> <script setup lang="ts">
import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui'; import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui'
import { getVxePopupContainer } from '@vben/utils'; import { getVxePopupContainer } from '@vben/utils'
import { Modal, Popconfirm, Space } from 'ant-design-vue'; import { Modal, Popconfirm, Space } from 'ant-design-vue'
import { import {
useVbenVxeGrid, useVbenVxeGrid,
vxeCheckboxChecked, vxeCheckboxChecked,
type VxeGridProps, type VxeGridProps,
} from '#/adapter/vxe-table'; } from '#/adapter/vxe-table'
import { import {
accessControlExport, accessControlExport,
accessControlList, accessControlList,
accessControlRemove, accessControlRemove,
accessControlSync accessControlSync
} from '#/api/sis/accessControl'; } from '#/api/sis/accessControl'
import type { AccessControlForm } from '#/api/sis/accessControl/model'; import type { AccessControlForm } from '#/api/sis/accessControl/model'
import { commonDownloadExcel } from '#/utils/file/download'; import { commonDownloadExcel } from '#/utils/file/download'
import accessControlModal from './accessControlModal.vue'; import accessControlModal from './accessControlModal.vue'
import { columns, querySchema } from './data'; import { columns, querySchema } from './data'
const formOptions: VbenFormProps = { const formOptions: VbenFormProps = {
commonConfig: { commonConfig: {
@ -40,7 +40,7 @@ const formOptions: VbenFormProps = {
// ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'], // ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
// ], // ],
// ], // ],
}; }
const gridOptions: VxeGridProps = { const gridOptions: VxeGridProps = {
checkboxConfig: { checkboxConfig: {
@ -64,7 +64,7 @@ const gridOptions: VxeGridProps = {
pageNum: page.currentPage, pageNum: page.currentPage,
pageSize: page.pageSize, pageSize: page.pageSize,
...formValues, ...formValues,
}); })
}, },
}, },
}, },
@ -73,49 +73,49 @@ const gridOptions: VxeGridProps = {
}, },
// //
id: 'property-accessControl-index', id: 'property-accessControl-index',
}; }
const [BasicTable, tableApi] = useVbenVxeGrid({ const [BasicTable, tableApi] = useVbenVxeGrid({
formOptions, formOptions,
gridOptions, gridOptions,
}); })
const [AccessControlModal, modalApi] = useVbenModal({ const [AccessControlModal, modalApi] = useVbenModal({
connectedComponent: accessControlModal, connectedComponent: accessControlModal,
}); })
function handleAdd() { function handleAdd() {
modalApi.setData({}); modalApi.setData({})
modalApi.open(); modalApi.open()
} }
async function handleEdit(row: Required<AccessControlForm>) { async function handleEdit(row: Required<AccessControlForm>) {
modalApi.setData({ id: row.id }); modalApi.setData({ id: row.id })
modalApi.open(); modalApi.open()
} }
async function handleDelete(row: Required<AccessControlForm>) { async function handleDelete(row: Required<AccessControlForm>) {
await accessControlRemove(row.id); await accessControlRemove(row.id)
await tableApi.query(); await tableApi.query()
} }
async function handleSyncE8() { async function handleSyncE8() {
await accessControlSync(); await accessControlSync()
await tableApi.query(); await tableApi.query()
} }
function handleMultiDelete() { function handleMultiDelete() {
const rows = tableApi.grid.getCheckboxRecords(); const rows = tableApi.grid.getCheckboxRecords()
const ids = rows.map((row: Required<AccessControlForm>) => row.id); const ids = rows.map((row: Required<AccessControlForm>) => row.id)
Modal.confirm({ Modal.confirm({
title: '提示', title: '提示',
okType: 'danger', okType: 'danger',
content: `确认删除选中的${ids.length}条记录吗?`, content: `确认删除选中的${ids.length}条记录吗?`,
onOk: async () => { onOk: async () => {
await accessControlRemove(ids); await accessControlRemove(ids)
await tableApi.query(); await tableApi.query()
}, },
}); })
} }
function handleDownloadExcel() { function handleDownloadExcel() {
@ -126,7 +126,7 @@ function handleDownloadExcel() {
{ {
fieldMappingTime: formOptions.fieldMappingTime, fieldMappingTime: formOptions.fieldMappingTime,
}, },
); )
} }
</script> </script>
@ -136,49 +136,23 @@ function handleDownloadExcel() {
<template #toolbar-tools> <template #toolbar-tools>
<Space> <Space>
<a-button @click="handleSyncE8">同步</a-button> <a-button @click="handleSyncE8">同步</a-button>
<a-button <a-button v-access:code="['property:accessControl:export']" @click="handleDownloadExcel">
v-access:code="['property:accessControl:export']"
@click="handleDownloadExcel"
>
{{ $t('pages.common.export') }} {{ $t('pages.common.export') }}
</a-button> </a-button>
<a-button <a-button :disabled="!vxeCheckboxChecked(tableApi)" danger type="primary"
:disabled="!vxeCheckboxChecked(tableApi)" v-access:code="['property:accessControl:remove']" @click="handleMultiDelete">
danger
type="primary"
v-access:code="['property:accessControl:remove']"
@click="handleMultiDelete"
>
{{ $t('pages.common.delete') }} {{ $t('pages.common.delete') }}
</a-button> </a-button>
<a-button
type="primary"
v-access:code="['property:accessControl:add']"
@click="handleAdd"
>
{{ $t('pages.common.add') }}
</a-button>
</Space> </Space>
</template> </template>
<template #action="{ row }"> <template #action="{ row }">
<Space> <Space>
<ghost-button <ghost-button v-access:code="['property:accessControl:edit']" @click.stop="handleEdit(row)">
v-access:code="['property:accessControl:edit']"
@click.stop="handleEdit(row)"
>
{{ $t('pages.common.edit') }} {{ $t('pages.common.edit') }}
</ghost-button> </ghost-button>
<Popconfirm <Popconfirm :get-popup-container="getVxePopupContainer" placement="left" title="确认删除?"
:get-popup-container="getVxePopupContainer" @confirm="handleDelete(row)">
placement="left" <ghost-button danger v-access:code="['property:accessControl:remove']" @click.stop="">
title="确认删除?"
@confirm="handleDelete(row)"
>
<ghost-button
danger
v-access:code="['property:accessControl:remove']"
@click.stop=""
>
{{ $t('pages.common.delete') }} {{ $t('pages.common.delete') }}
</ghost-button> </ghost-button>
</Popconfirm> </Popconfirm>

View File

@ -60,6 +60,9 @@ const [BasicModal, modalApi] = useVbenModal({
isUpdate.value = !!id isUpdate.value = !!id
if (isUpdate.value && id) { if (isUpdate.value && id) {
const record = await authGroupInfo(id) const record = await authGroupInfo(id)
checkedKeys.value = (record.acIds || []).concat(record.floorIds || [])
await formApi.setValues(record) await formApi.setValues(record)
} }
await markInitialized() await markInitialized()
@ -82,9 +85,9 @@ async function handleConfirm() {
} }
const data = cloneDeep(await formApi.getValues()) const data = cloneDeep(await formApi.getValues())
data.acIds = acIds.value; data.acIds = acIds.value
data.eleIds = eleIds.value; data.eleIds = eleIds.value
data.floorIds = floorIds.value; data.floorIds = floorIds.value
await (isUpdate.value ? authGroupUpdate(data) : authGroupAdd(data)) await (isUpdate.value ? authGroupUpdate(data) : authGroupAdd(data))
resetInitialized() resetInitialized()
emit('reload') emit('reload')
@ -98,6 +101,7 @@ async function handleConfirm() {
async function handleClosed() { async function handleClosed() {
await formApi.resetForm() await formApi.resetForm()
checkedKeys.value = []
resetInitialized() resetInitialized()
} }

View File

@ -100,6 +100,11 @@ export const modalSchema: FormSchemaGetter = () => [
component: 'Input', component: 'Input',
rules: 'required', rules: 'required',
}, },
{
label: '设备位置',
fieldName: 'floorId',
component: 'TreeSelect',
},
{ {
label: '设备厂商', label: '设备厂商',
fieldName: 'factoryNo', fieldName: 'factoryNo',

View File

@ -1,28 +1,29 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref } from 'vue'; import { computed, ref } from 'vue'
import { useVbenModal } from '@vben/common-ui'; import { useVbenModal } from '@vben/common-ui'
import { $t } from '@vben/locales'; import { $t } from '@vben/locales'
import { cloneDeep } from '@vben/utils'; import { cloneDeep, getPopupContainer, handleNode } from '@vben/utils'
import { useVbenForm } from '#/adapter/form'; import { useVbenForm } from '#/adapter/form'
import { import {
deviceManageAdd, deviceManageAdd,
deviceManageInfo, deviceManageInfo,
deviceManageUpdate, deviceManageUpdate,
} from '#/api/sis/deviceManage'; } from '#/api/sis/deviceManage'
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup'; import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup'
import { modalSchema } from './data'; import { modalSchema } from './data'
import { getDictOptions } from '#/utils/dict'; import { communityTree } from '#/api/property/community'
import { DictEnum } from '@vben/constants'; import { getDictOptions } from '#/utils/dict'
import { DictEnum } from '@vben/constants'
const emit = defineEmits<{ reload: [] }>(); const emit = defineEmits<{ reload: [] }>()
const isUpdate = ref(false); const isUpdate = ref(false)
const title = computed(() => { const title = computed(() => {
return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add'); return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add')
}); })
const [BasicForm, formApi] = useVbenForm({ const [BasicForm, formApi] = useVbenForm({
commonConfig: { commonConfig: {
@ -38,14 +39,14 @@ const [BasicForm, formApi] = useVbenForm({
schema: modalSchema(), schema: modalSchema(),
showDefaultActions: false, showDefaultActions: false,
wrapperClass: 'grid-cols-2', wrapperClass: 'grid-cols-2',
}); })
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff( const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
{ {
initializedGetter: defaultFormValueGetter(formApi), initializedGetter: defaultFormValueGetter(formApi),
currentGetter: defaultFormValueGetter(formApi), currentGetter: defaultFormValueGetter(formApi),
}, },
); )
const [BasicModal, modalApi] = useVbenModal({ const [BasicModal, modalApi] = useVbenModal({
// //
@ -56,45 +57,88 @@ const [BasicModal, modalApi] = useVbenModal({
onConfirm: handleConfirm, onConfirm: handleConfirm,
onOpenChange: async (isOpen) => { onOpenChange: async (isOpen) => {
if (!isOpen) { if (!isOpen) {
return null; return null
} }
modalApi.modalLoading(true);
const { id } = modalApi.getData() as { id?: number | string }; //
isUpdate.value = !!id; setupCommunitySelect()
modalApi.modalLoading(true)
const { id } = modalApi.getData() as { id?: number | string }
isUpdate.value = !!id
if (isUpdate.value && id) { if (isUpdate.value && id) {
const record = await deviceManageInfo(id); const record = await deviceManageInfo(id)
await formApi.setValues(record); await formApi.setValues(record)
} }
await markInitialized(); await markInitialized()
modalApi.modalLoading(false); modalApi.modalLoading(false)
}, },
}); })
async function handleConfirm() { async function handleConfirm() {
try { try {
modalApi.lock(true); modalApi.lock(true)
const { valid } = await formApi.validate(); const { valid } = await formApi.validate()
if (!valid) { if (!valid) {
return; return
} }
// getValuesreadonly // getValuesreadonly
const data = cloneDeep(await formApi.getValues()); const data = cloneDeep(await formApi.getValues())
await (isUpdate.value ? deviceManageUpdate(data) : deviceManageAdd(data)); await (isUpdate.value ? deviceManageUpdate(data) : deviceManageAdd(data))
resetInitialized(); resetInitialized()
emit('reload'); emit('reload')
modalApi.close(); modalApi.close()
} catch (error) { } catch (error) {
console.error(error); console.error(error)
} finally { } finally {
modalApi.lock(false); modalApi.lock(false)
} }
} }
/**
* 初始化城市
*/
async function setupCommunitySelect() {
const areaList = await communityTree(3)
// /
// addFullName(areaList, 'areaName', ' / ');
const splitStr = '/'
handleNode(areaList, 'label', splitStr, function (node: any) {
if (node.level != 3) {
node.disabled = true
}
})
formApi.updateSchema([
{
componentProps: () => ({
class: 'w-full',
fieldNames: {
key: 'id',
label: 'label',
value: 'code',
children: 'children',
},
getPopupContainer,
placeholder: '请选择楼层',
showSearch: true,
treeData: areaList,
treeDefaultExpandAll: true,
treeLine: { showLeafIcon: false },
//
treeNodeFilterProp: 'label',
//
treeNodeLabelProp: 'fullName',
}),
fieldName: 'floorId',
},
])
}
async function handleClosed() { async function handleClosed() {
await formApi.resetForm(); await formApi.resetForm()
resetInitialized(); resetInitialized()
} }
</script> </script>