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

This commit is contained in:
fyy
2025-08-07 17:45:36 +08:00
12 changed files with 161 additions and 77 deletions

View File

@@ -70,6 +70,10 @@ export interface VisitorManagementVO {
* 预约状态0待确认1已确认2已取消3已完成 * 预约状态0待确认1已确认2已取消3已完成
*/ */
serveStatus: number; serveStatus: number;
/**
* 身份证号
*/
idCard: string;
} }
export interface VisitorManagementForm extends BaseEntity { export interface VisitorManagementForm extends BaseEntity {

View File

@@ -2,12 +2,12 @@ import type {
AccessControlForm, AccessControlForm,
AccessControlQuery, AccessControlQuery,
AccessControlVO, AccessControlVO,
} from './model' } from './model';
import type { ID, IDS, PageResult, TreeNode } from '#/api/common' import type { ID, IDS, PageResult, TreeNode } from '#/api/common';
import { commonExport } from '#/api/helper' import { commonExport } from '#/api/helper';
import { requestClient } from '#/api/request' import { requestClient } from '#/api/request';
/** /**
* 查询门禁管理列表 * 查询门禁管理列表
@@ -18,7 +18,7 @@ export function accessControlList(params?: AccessControlQuery) {
return requestClient.get<PageResult<AccessControlVO>>( return requestClient.get<PageResult<AccessControlVO>>(
'/sis/accessControl/list', '/sis/accessControl/list',
{ params }, { params },
) );
} }
/** /**
@@ -27,7 +27,7 @@ export function accessControlList(params?: AccessControlQuery) {
* @returns 门禁管理列表 * @returns 门禁管理列表
*/ */
export function accessControlExport(params?: AccessControlQuery) { export function accessControlExport(params?: AccessControlQuery) {
return commonExport('/sis/accessControl/export', params ?? {}) return commonExport('/sis/accessControl/export', params ?? {});
} }
/** /**
@@ -36,7 +36,7 @@ export function accessControlExport(params?: AccessControlQuery) {
* @returns 门禁管理详情 * @returns 门禁管理详情
*/ */
export function accessControlInfo(id: ID) { export function accessControlInfo(id: ID) {
return requestClient.get<AccessControlVO>(`/sis/accessControl/${id}`) return requestClient.get<AccessControlVO>(`/sis/accessControl/${id}`);
} }
/** /**
@@ -45,7 +45,7 @@ export function accessControlInfo(id: ID) {
* @returns void * @returns void
*/ */
export function accessControlAdd(data: AccessControlForm) { export function accessControlAdd(data: AccessControlForm) {
return requestClient.postWithMsg<void>('/sis/accessControl', data) return requestClient.postWithMsg<void>('/sis/accessControl', data);
} }
/** /**
@@ -54,7 +54,7 @@ export function accessControlAdd(data: AccessControlForm) {
* @returns void * @returns void
*/ */
export function accessControlUpdate(data: AccessControlForm) { export function accessControlUpdate(data: AccessControlForm) {
return requestClient.putWithMsg<void>('/sis/accessControl', data) return requestClient.putWithMsg<void>('/sis/accessControl', data);
} }
/** /**
@@ -63,7 +63,7 @@ export function accessControlUpdate(data: AccessControlForm) {
* @returns void * @returns void
*/ */
export function accessControlRemove(id: ID | IDS) { export function accessControlRemove(id: ID | IDS) {
return requestClient.deleteWithMsg<void>(`/sis/accessControl/${id}`) return requestClient.deleteWithMsg<void>(`/sis/accessControl/${id}`);
} }
/** /**
@@ -71,7 +71,7 @@ export function accessControlRemove(id: ID | IDS) {
* @returns void * @returns void
*/ */
export function queryTree() { export function queryTree() {
return requestClient.get<TreeNode<Number>[]>(`/sis/accessControl/tree`) return requestClient.get<TreeNode<Number>[]>(`/sis/accessControl/tree`);
} }
/** /**
@@ -79,5 +79,12 @@ export function queryTree() {
* @returns void * @returns void
*/ */
export function accessControlSync() { export function accessControlSync() {
return requestClient.get<void>(`/sis/accessControl/sync`) return requestClient.get<void>(`/sis/accessControl/sync`);
}
export function remoteOpenDoor(params: any) {
return requestClient.post<void>(
`/sis/accessControl/e8/remoteOpenDoor`,
params,
);
} }

View File

@@ -63,7 +63,6 @@ const [BasicModal, modalApi] = useVbenModal({
]; ];
} }
record.status = record.status?.toString(); record.status = record.status?.toString();
console.log(record);
await formApi.setValues(record); await formApi.setValues(record);
} }
await markInitialized(); await markInitialized();

View File

@@ -188,7 +188,7 @@ const modalSchema = [
}, },
}, },
{ {
label: '联系电话', label: '评价图片',
fieldName: 'imgUrl', fieldName: 'imgUrl',
component: 'Input', component: 'Input',
dependencies: { dependencies: {
@@ -196,6 +196,30 @@ const modalSchema = [
triggerFields: [''], triggerFields: [''],
}, },
}, },
{
label: '签到方式',
fieldName: 'signType',
component: 'Select',
componentProps: {
options:getDictOptions('wy_bjqdfs')
},
dependencies: {
show: () => (isReadonly.value ? true : false),
triggerFields: [''],
},
},
{
label: '签到图片',
fieldName: 'signImgUrl',
component: 'ImageUpload',
componentProps: {
helpMessage:false
},
dependencies: {
show: (formValue) => (isReadonly.value&&formValue.signImgUrl ? true : false),
triggerFields: [''],
},
},
]; ];
const [BasicForm, formApi] = useVbenForm({ const [BasicForm, formApi] = useVbenForm({
commonConfig: { commonConfig: {

View File

@@ -115,7 +115,6 @@ async function fetchOrderTyper() {
const totalQuantity = board.value.satisfactionChartList.reduce((sum, item) => { const totalQuantity = board.value.satisfactionChartList.reduce((sum, item) => {
return sum + Number(item.quantity || 0); return sum + Number(item.quantity || 0);
}, 0); }, 0);
console.log(seriesData.value)
renderOrderTyper({ renderOrderTyper({
title: {text: '工单类型分类占比',left: '18px',top: '18px'}, title: {text: '工单类型分类占比',left: '18px',top: '18px'},
tooltip: { tooltip: {
@@ -127,7 +126,13 @@ async function fetchOrderTyper() {
orient: 'vertical', orient: 'vertical',
icon: 'circle', icon: 'circle',
itemWidth: 8, itemWidth: 8,
itemHeight: 8 itemHeight: 8,
formatter: (name) => {
const dataItem = seriesData.value.find(item => item.name === name);
const value = dataItem?.value || 0;
const percentage = totalQuantity ? ((value / totalQuantity) * 100).toFixed(1) : 0;
return `${name} ${percentage}% ${value}`;
},
}, },
series: [ series: [
{ {

View File

@@ -154,6 +154,6 @@ const handleUpdate = (dataSet) => {
</Space> </Space>
</template> </template>
</BasicTable> </BasicTable>
<InspectionRouteModal @reload="tableApi.query()" @update-data="handleUpdate"/> <InspectionRouteModal @update-data="handleUpdate"/>
</Page> </Page>
</template> </template>

View File

@@ -7,7 +7,6 @@ import { useVbenForm } from '#/adapter/form';
import { import {
inspectionRouteAdd, inspectionRouteAdd,
inspectionRouteInfo, inspectionRouteInfo,
inspectionRouteList,
inspectionRouteUpdate inspectionRouteUpdate
} from '#/api/property/inspectionManagement/inspectionRoute'; } from '#/api/property/inspectionManagement/inspectionRoute';
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup'; import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
@@ -62,11 +61,14 @@ const [BasicModal, modalApi] = useVbenModal({
if (isUpdate.value && id) { if (isUpdate.value && id) {
const record = await inspectionRouteInfo(id); const record = await inspectionRouteInfo(id);
pointList.value = (record.inspectionRoutePointVoList || []).map(item => ({ pointList.value = (record.inspectionRoutePointVoList || []).map(item => ({
id: item.id,
pointId: item.pointId ?? '', pointId: item.pointId ?? '',
pointName: item.pointName ?? '', pointName: item.pointName ?? '',
startTime: item.startTime ?? '',
endTime: item.endTime ?? '',
sort: item.sort ?? '',
})); }));
await tableApi.reload(); await tableApi.reload();
console.log(pointList.value,111)
await formApi.setValues(record); await formApi.setValues(record);
} }
await markInitialized(); await markInitialized();
@@ -83,10 +85,10 @@ async function handleConfirm() {
} }
let data = { let data = {
...cloneDeep(await formApi.getValues()), ...cloneDeep(await formApi.getValues()),
inspectionRoutePointBoList:[pointData.value] inspectionRoutePointBoList:[...pointList.value]
} }
console.log(data,333)
await (isUpdate.value ? inspectionRouteUpdate(data) : inspectionRouteAdd(data)); await (isUpdate.value ? inspectionRouteUpdate(data) : inspectionRouteAdd(data));
pointList.value = []
resetInitialized(); resetInitialized();
emit('reload'); emit('reload');
modalApi.close(); modalApi.close();
@@ -99,9 +101,11 @@ async function handleConfirm() {
async function handleClosed() { async function handleClosed() {
await formApi.resetForm(); await formApi.resetForm();
pointList.value = []
resetInitialized(); resetInitialized();
} }
const pointItem = ref([])
async function queryWorkOrdersType() { async function queryWorkOrdersType() {
let params = { let params = {
pageSize: 1000, pageSize: 1000,
@@ -112,6 +116,10 @@ async function queryWorkOrdersType() {
label: item.pointName, label: item.pointName,
value: item.id, value: item.id,
})); }));
pointItem.value = res.rows.map((item) => ({
pointId: item.id,
pointName: item.pointName,
}));
tableApi.formApi.updateSchema([{ tableApi.formApi.updateSchema([{
componentProps: () => ({ componentProps: () => ({
options: options, options: options,
@@ -166,7 +174,6 @@ const gridOptions: VxeGridProps = {
}; };
const [BasicTable, tableApi] = useVbenVxeGrid({ const [BasicTable, tableApi] = useVbenVxeGrid({
formOptions,
gridOptions, gridOptions,
}); });
@@ -180,15 +187,20 @@ function handleAdd() {
} }
async function handleEdit(row: Required<InspectionRouteForm>) { async function handleEdit(row: Required<InspectionRouteForm>) {
pointModalApi.setData({ id: row.id }); pointModalApi.setData({ row });
pointModalApi.open(); pointModalApi.open();
} }
const pointData = ref({})
const handlePoint = (data) => { const handlePoint = (data) => {
data.startTime = dayjs(data.startTime).format('YYYY-MM-DD HH:mm:ss') data.startTime = dayjs(data.startTime).format('YYYY-MM-DD HH:mm:ss')
data.endTime = dayjs(data.endTime).format('YYYY-MM-DD HH:mm:ss') data.endTime = dayjs(data.endTime).format('YYYY-MM-DD HH:mm:ss')
pointData.value = data; data.pointName = pointItem.value.find(item => item.pointId === data.pointId)?.pointName;
const existingIndex = pointList.value.findIndex(item => item.pointId === data.pointId);
if (existingIndex !== -1) {
pointList.value[existingIndex] = data;
} else {
pointList.value.push(data);
}
}; };
</script> </script>
@@ -196,7 +208,7 @@ const handlePoint = (data) => {
<BasicModal :title="title"> <BasicModal :title="title">
<BasicForm /> <BasicForm />
<Page :auto-content-height="true" style="background-color: #F1F3F6"> <Page :auto-content-height="true" style="background-color: #F1F3F6">
<BasicTable table-title="巡检点" :grid-options="gridOptions"> <BasicTable table-title="巡检点" :grid-options="{ ...gridOptions, data: pointList, pagerConfig: { total: pointList.length } }">
<template #toolbar-tools> <template #toolbar-tools>
<Space> <Space>
<a-button <a-button
@@ -217,7 +229,7 @@ const handlePoint = (data) => {
</Space> </Space>
</template> </template>
</BasicTable> </BasicTable>
<PointModal @reload="tableApi.query()" @update-data="handlePoint"/> <PointModal @reload="tableApi.query()" @update-data="handlePoint" :pointList="pointList"/>
</Page> </Page>
</BasicModal> </BasicModal>
</template> </template>

View File

@@ -2,7 +2,7 @@
import { useVbenModal } from '@vben/common-ui'; import { useVbenModal } from '@vben/common-ui';
import { cloneDeep } from '@vben/utils'; import { cloneDeep } from '@vben/utils';
import { useVbenForm } from '#/adapter/form'; import { useVbenForm } from '#/adapter/form';
import { inspectionRouteInfo } from '#/api/property/inspectionManagement/inspectionRoute'; import dayjs from 'dayjs';
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup'; import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
import { import {
inspectionPointList, inspectionPointList,
@@ -34,6 +34,13 @@ const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
}, },
); );
const props = defineProps({
pointList: {
type: Array,
default: () => [],
},
});
const [BasicModal, modalApi] = useVbenModal({ const [BasicModal, modalApi] = useVbenModal({
class: 'w-[550px]', class: 'w-[550px]',
fullscreenButton: false, fullscreenButton: false,
@@ -45,13 +52,14 @@ const [BasicModal, modalApi] = useVbenModal({
return null; return null;
} }
modalApi.modalLoading(true); modalApi.modalLoading(true);
const { row } = modalApi.getData() as { row?: number | string };
isUpdate.value = !!row;
await queryWorkOrdersType() await queryWorkOrdersType()
const { id } = modalApi.getData() as { id?: number | string }; if (isUpdate.value && row ){
isUpdate.value = !!id; row.startTime = dayjs(row.startTime)
row.endTime = dayjs(row.endTime)
if (isUpdate.value && id) { console.log(row,456)
const record = await inspectionRouteInfo(id); await formApi.setValues(row);
await formApi.setValues(record);
} }
await markInitialized(); await markInitialized();
@@ -89,15 +97,26 @@ async function queryWorkOrdersType() {
pageNum: 1 pageNum: 1
} }
const res = await inspectionPointList(params) const res = await inspectionPointList(params)
const options = res.rows.map((item) => ({ let options = []
if(isUpdate.value){
options = res.rows.map((item) => ({
label: item.pointName, label: item.pointName,
value: item.id, value: item.id,
})); }));
}else{
const existingIds = props.pointList.map(item => item.pointId);
const filteredRows = res.rows.filter(item => !existingIds.includes(item.id));
options = filteredRows.map((item) => ({
label: item.pointName,
value: item.id,
}));
}
formApi.updateSchema([{ formApi.updateSchema([{
componentProps: () => ({ componentProps: () => ({
options: options, options: options,
showSearch: true, showSearch: true,
filterOption: filterOption, filterOption: filterOption,
disabled: isUpdate.value,
}), }),
fieldName: 'pointId', fieldName: 'pointId',
}]) }])

View File

@@ -34,13 +34,19 @@ async function handleOpenChange(open: boolean) {
<template> <template>
<BasicModal :footer="false" :fullscreen-button="false" title="访客管理信息" class="w-[70%]"> <BasicModal :footer="false" :fullscreen-button="false" title="访客管理信息" class="w-[70%]">
<Descriptions v-if="visitorTodoDetail" size="small" :column="2" bordered :labelStyle="{width:'100px'}"> <Descriptions v-if="visitorTodoDetail" size="small" :column="2" bordered :labelStyle="{width:'120px'}">
<DescriptionsItem label="访客姓名"> <DescriptionsItem label="访客姓名">
{{ visitorTodoDetail.visitorName }} {{ visitorTodoDetail.visitorName }}
</DescriptionsItem> </DescriptionsItem>
<DescriptionsItem label="访客电话"> <DescriptionsItem label="访客电话">
{{ visitorTodoDetail.visitorPhone }} {{ visitorTodoDetail.visitorPhone }}
</DescriptionsItem> </DescriptionsItem>
<DescriptionsItem label="访客身份证">
{{ visitorTodoDetail.idCard }}
</DescriptionsItem>
<DescriptionsItem label="人脸图片">
{{ visitorTodoDetail.facePictures }}
</DescriptionsItem>
<DescriptionsItem label="所属公司"> <DescriptionsItem label="所属公司">
{{ visitorTodoDetail.visitorUnit}} {{ visitorTodoDetail.visitorUnit}}
</DescriptionsItem> </DescriptionsItem>

View File

@@ -2,7 +2,7 @@
import { onMounted, ref, toRaw } from 'vue'; import { onMounted, ref, toRaw } from 'vue';
import { SyncOutlined } from '@ant-design/icons-vue'; import { SyncOutlined } from '@ant-design/icons-vue';
import { InputSearch, message, Skeleton, Tree } from 'ant-design-vue'; import { InputSearch, message, Skeleton, Tree } from 'ant-design-vue';
import { queryTree } from '#/api/sis/accessControl'; import { queryTree, remoteOpenDoor } from '#/api/sis/accessControl';
import type { TreeNode } from '#/api/common'; import type { TreeNode } from '#/api/common';
defineOptions({ inheritAttrs: false }); defineOptions({ inheritAttrs: false });
@@ -57,13 +57,14 @@ function open() {
const acArr = checkNodeData(); const acArr = checkNodeData();
if (acArr) { if (acArr) {
console.log(acArr); console.log(acArr);
remoteOpenDoor({ acIds: acArr, type: 0 });
} }
} }
function close() { function close() {
const acArr = checkNodeData(); const acArr = checkNodeData();
if (acArr) { if (acArr) {
console.log(acArr); remoteOpenDoor({ acIds: acArr, type: 1 });
} }
} }
@@ -71,6 +72,7 @@ function alwaysOpen() {
const acArr = checkNodeData(); const acArr = checkNodeData();
if (acArr) { if (acArr) {
console.log(acArr); console.log(acArr);
remoteOpenDoor({ acIds: acArr, type: 2 });
} }
} }
@@ -78,6 +80,7 @@ function reSet() {
const acArr = checkNodeData(); const acArr = checkNodeData();
if (acArr) { if (acArr) {
console.log(acArr); console.log(acArr);
remoteOpenDoor({ acIds: acArr, type: 4 });
} }
} }
@@ -92,7 +95,7 @@ function checkNodeData() {
arr.forEach((item) => { arr.forEach((item) => {
const node: any = checkData[item]; const node: any = checkData[item];
if (node.level == 5) { if (node.level == 5) {
acArr.push(node); acArr.push(node.id);
} }
}); });
if (!acArr || acArr.length === 0) { if (!acArr || acArr.length === 0) {
@@ -116,8 +119,8 @@ function onTreeCheck(_keys: any, nodes: any) {
delete checkData[id]; delete checkData[id];
} }
}); });
const nodes = toRaw(checkedNodes); const data = toRaw(checkedNodes);
emit('checked', nodes); emit('checked', checked, data);
} }
onMounted(loadChannelTree); onMounted(loadChannelTree);

View File

@@ -1,7 +1,7 @@
<template> <template>
<Page :auto-content-height="true"> <Page :auto-content-height="true">
<div class="flex h-full gap-[8px]"> <div class="flex h-full gap-[8px]">
<DpTree class="h-[87vh] w-[300px]" @check="onNodeChecked" /> <DpTree class="h-[87vh] w-[300px]" @checked="onNodeChecked" />
<div class="bg-background flex-1"> <div class="bg-background flex-1">
<div class="video-play-area flex h-full flex-wrap"> <div class="video-play-area flex h-full flex-wrap">
<div <div
@@ -28,9 +28,9 @@
import DpTree from './dp-tree.vue'; import DpTree from './dp-tree.vue';
import { Page } from '@vben/common-ui'; import { Page } from '@vben/common-ui';
import { ref } from 'vue'; import { ref } from 'vue';
import mpegts from "mpegts.js"; import mpegts from 'mpegts.js';
import {addStreamProxy} from "#/api/sis/stream"; import { addStreamProxy } from '#/api/sis/stream';
import {message} from "ant-design-vue"; import { message } from 'ant-design-vue';
/** /**
* 屏幕播放器数量 * 屏幕播放器数量
@@ -61,14 +61,28 @@ const setItemRef = (el: any) => {
} }
}; };
function onNodeChecked(nodes: any[]) { function onNodeChecked(checked, nodes: any[]) {
if (checked) {
console.log(nodes); console.log(nodes);
nodes.forEach((node: any) => {
const { data, level } = node;
// 只播放视频节点
if (level == 6) {
const index =
currentSelectPlayerIndex.value === -1
? 0
: currentSelectPlayerIndex.value;
doPlayer(data, index);
}
});
} else {
}
} }
// 播放器数据, 每一个位置代表页面上行的一个矩形 // 播放器数据, 每一个位置代表页面上行的一个矩形
const playerList: any[] = []; const playerList: any[] = [];
/** /**
* 开始播放视频流 * 开始播放视频流
* @param nodeData 播放的节点数据 * @param nodeData 播放的节点数据
@@ -77,24 +91,13 @@ const playerList: any[] = [];
function doPlayer(nodeData: any, index: number = 0) { function doPlayer(nodeData: any, index: number = 0) {
console.log('index=', index); console.log('index=', index);
if (mpegts.isSupported()) { if (mpegts.isSupported()) {
let params = {}; const params = {
// if (nodeData.nvrIp) {
// params = {
// videoIp: nodeData.nvrIp,
// videoPort: nodeData.nvrPort,
// factoryNo: nodeData.nvrFactoryNo,
// account: nodeData.nvrAccount,
// pwd: nodeData.nvrPwd,
// channelId: nodeData.nvrChannelNo,
// };
// } else {
params = {
videoIp: nodeData.deviceIp, videoIp: nodeData.deviceIp,
videoPort: nodeData.devicePort, videoPort: 554,
factoryNo: nodeData.factoryNo, factoryNo: nodeData.factoryNo,
account: nodeData.deviceAccount, account: nodeData.deviceAccount,
pwd: nodeData.devicePwd, pwd: nodeData.devicePwd,
channelId: nodeData.channelNo, channelId: nodeData.channelNo ? nodeData.channelNo : 101,
}; };
// } // }
addStreamProxy(params).then((res) => { addStreamProxy(params).then((res) => {
@@ -136,7 +139,6 @@ function doPlayer(nodeData: any, index: number = 0) {
} }
} }
function changeElPlayer(playerInfo: any, index: number) { function changeElPlayer(playerInfo: any, index: number) {
const playerData = playerInfo.data; const playerData = playerInfo.data;
const oldPlayer = playerInfo.player; const oldPlayer = playerInfo.player;
@@ -173,7 +175,6 @@ function changeElPlayer(playerInfo: any, index: number) {
} }
} }
function closePlayVieo(plInfo: any) { function closePlayVieo(plInfo: any) {
if (plInfo) { if (plInfo) {
try { try {
@@ -201,9 +202,6 @@ function closePlayer(index: number) {
} }
} }
} }
</script> </script>
<style> <style>
.player { .player {

View File

@@ -111,11 +111,12 @@ async function handleConfirm() {
const data = cloneDeep(await formApi.getValues()) const data = cloneDeep(await formApi.getValues())
// 通道信息 // 通道信息
const filteredChannels = dynamicValidateForm.floor const filteredChannels = dynamicValidateForm.floor
.filter(item => !(item.out.length === 0 && item.in.length === 0)) .filter(item => !(item.outUp.length === 0 && item.outDown.length === 0 && item.in.length === 0))
.map(item => ({ .map(item => ({
floorId: item.id, floorId: item.id,
inChannel: item.in, inChannel: item.in,
outChannel: item.out upChannel: item.outUp,
downChannel: item.outDown,
})) }))
data.channels = filteredChannels data.channels = filteredChannels
@@ -223,7 +224,8 @@ async function setupCommunitySelect() {
} }
interface floor { interface floor {
out: string outUp: string
outDown: string
in: string in: string
num: string | number num: string | number
id: string | number id: string | number
@@ -238,7 +240,8 @@ async function handleGetFloor(unitId: string | number) {
floorList.value = [] floorList.value = []
res.forEach((item) => { res.forEach((item) => {
floorList.value.push({ floorList.value.push({
out: '', outUp: '',
outDown: '',
in: '', in: '',
num: item.floorNumber, num: item.floorNumber,
id: item.id, id: item.id,
@@ -268,10 +271,14 @@ async function handleClosed() {
<Form :model="dynamicValidateForm" layout="inline"> <Form :model="dynamicValidateForm" layout="inline">
<Space v-for="(floor, index) in dynamicValidateForm.floor" :key="floor.id" <Space v-for="(floor, index) in dynamicValidateForm.floor" :key="floor.id"
style="display: flex; margin-bottom: 8px" align="baseline"> style="display: flex; margin-bottom: 8px" align="baseline">
<FormItem :label="'楼层' + (floor.num)" :name="['floor', index, 'out']"> <span>{{ "楼层"+floor.num }}</span>
<Input v-model:value="floor.out" placeholder="外部按键通道" /> <FormItem label="上键通道" :name="['floor', index, 'outUp']">
<Input v-model:value="floor.outUp" placeholder="外部按键通道" />
</FormItem> </FormItem>
<FormItem :name="['floor', index, 'in']"> <FormItem label="下键通道" :name="['floor', index, 'outDown']">
<Input v-model:value="floor.outDown" placeholder="内部按键通道" />
</FormItem>
<FormItem label="楼层通道" :name="['floor', index, 'in']">
<Input v-model:value="floor.in" placeholder="内部按键通道" /> <Input v-model:value="floor.in" placeholder="内部按键通道" />
</FormItem> </FormItem>
</Space> </Space>