陶杰
2024-11-24 79e942ec0ab33b0e6b6590bdc51d005dfef8dadb
1.画板布局
已修改6个文件
711 ■■■■■ 文件已修改
src/api/area.js 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/device-info.vue 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/equ-add-form.vue 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/area/main-container.vue 584 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/screen1/itm-map-plant-board.vue 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/screen1/itm.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/area.js
@@ -175,6 +175,21 @@
  })
}
/**
 *
 * @returns 获取所有交换机列表
 */
export function getAllSwitch() {
  return request({
    url: '/api/services/app/SwitchDevice/GetAllSwitch',
    method: 'get',
    params: {
    }
  })
}
/**
 * 获取所有区域列表
 */
@@ -198,3 +213,16 @@
    }
  })
}
/**
 * 根据区域查找背景图和当前数量
 */
export function getAreaModuleBycode(code) {
  return request({
    url: '/api/services/app/SwitchDevice/GetAreaModuleBycode',
    method: 'get',
    params: {
      'areaCode': code
    }
  })
}
src/components/device-info.vue
@@ -90,10 +90,10 @@
        <div
          class="button-to-check"
          v-if="
            device_info?.status==1 ||
            device_info?.status==2 ||
            device_info?.status==3 ||
            device_info?.status==4
            device_info?.statusInt==1 ||
            device_info?.statusInt==2 ||
            device_info?.statusInt==3 ||
            device_info?.statusInt==4
          "
          @click="statusPort(index)"
@@ -220,7 +220,7 @@
      width: 49rem;
      position: absolute;
      // top: -31.5rem;
      top: -46.5rem;
      top: -44.9rem;
      transform: translate(-48%, 0%);
      left: 50%;
      z-index: 120;
@@ -330,6 +330,7 @@
.info-container {
  display: flex;
  justify-content: space-between;
  height:100%;
}
.info-block {
src/components/equ-add-form.vue
@@ -10,21 +10,51 @@
      <div class="equ-form-container">
        <div class="flex">
          <div class="label require">交换机:</div>
          <input
          <!-- <input
            class="value input"
            v-model="name"
            placeholder="请输入交换机名称"
            placeholder-class="value input"
          />
          /> -->
          <select
            class="value select"
            placeholder="请选择交换机"
            v-model="name"
            clearable filterable
          >
            <option disabled selected value >请选择交换机</option>
            <option  v-for="item in switchList"
               :key="item.id"
                :label="item.name"
                :value="item.id"
            >
            </option>
          </select>
        </div>
        <div class="flex m-t-2rem">
          <div class="label require">交换机柜:</div>
          <input
          <!-- <input
            class="value input"
            v-model="cabinetName"
            placeholder="请输入交换机柜名称"
            placeholder-class="value input"
          />
          /> -->
          <select
            class="value select"
            placeholder="请选择交换机柜"
            v-model="cabinetName"
            clearable filterable
          >
            <option disabled selected value >请选择交换机柜</option>
            <option  v-for="item in cabinetList"
               :key="item.id"
                :label="item.name"
                :value="item.id"
            >
            </option>
          </select>
        </div>
        <div class="flex m-t-2rem">
          <div class="label require">网桥:</div>
@@ -67,7 +97,7 @@
          <select
            class="value select"
            placeholder="请选择厂区"
            disabled
            disabled clearable filterable
            v-model="selectcode"
          >
            <!-- @change="updateDeviceList" -->
@@ -112,12 +142,13 @@
</template>
<script>
import { addDeviceInfo, getDeviceList } from "@/api/area";
import { addDeviceInfo, getDeviceList,getSwitchBord,getAllSwitch } from "@/api/area";
export default {
  props: {
    code: "",
    areas: [],
    init_device_list: [],
    cur_item: {},
  },
  data() {
    return {
@@ -138,6 +169,8 @@
      open: false,
      // selectswitchindex: "",
      cabinetList:[],
      switchList:[],
    };
  },
  mounted() {
@@ -145,8 +178,31 @@
      this.selectcode = this.code;
      this.device_list = this.init_device_list || [];
    }
    // 获取所有交换机柜
    this.getSwitchBord()
    // 获取所有交换柜
    this.getAllSwitch()
  },
  methods: {
    getSwitchBord(){
        getSwitchBord().then((res) => {
        this.cabinetList = res.cabinetList || [];
      });
    },
    getAllSwitch(){
      getAllSwitch().then((res) => {
        this.switchList = res.cabinetList || [];
      });
    },
    async updateDeviceList() {
      if (this.selectcode) {
        this.$modal.loading("加载中");
@@ -194,6 +250,10 @@
          cabinetName: this.cabinetName || "",
          areaCode: this.selectcode,
          switchName: this.name,
          areaRow:this.cur_item?.row,
          areaCell:this.cur_item?.cell,
        },
      };
      const re = await addDeviceInfo(dto);
@@ -245,6 +305,7 @@
      }
    },
  },
};
</script>
<style lang="scss">
src/views/area/main-container.vue
@@ -6,40 +6,29 @@
    // width:'100%',
    // height:'calc(100vh - 10rem)'
  }">
    <!-- @mousemove="handleMouseMove"
      @mouseup="handleMouseUp"
    <div id="content" class="equipments-container area-map" v-show="hideServe"
      @mousedown="handleMouseDown"
      @mouseleave="handleMouseLeave" -->
    <div id="content" class="equipments-container area-map" :class="['area-map-' + code]" v-show="hideServe"
      @mousemove="handleMouseMove" @mouseup="handleMouseUp" @mousedown="handleMouseDown" @mouseleave="handleMouseLeave"
      :style="{
        transform: `scale(${scale_container})`,
        width: screen_width + 'rem',
        height: screen_height + 'rem',
        // container_offset_x:''
        // container_offset_x:''
        'margin-left': `${container_offset_left}rem`,
        'margin-top': `${container_offset_top}rem`,
      }">
      <!-- <div class="bridge-group" v-for="group in bridge_infos" :key="group.code" :code="group.code">
        <bridge v-for="(item, index) of group.cells" :key="item.cell" :code="group.code" :areacode="code"
                @update_map="update_map" @update_status_indrag="update_status_indrag" @click_item="click_item"
                @click_item_add="click_item_add" @toSwitchInfo="toSwitchInfo" @delPort="delPort"
                @statusPort="statusPort"
                :current_drag_index="current_drag_index" :status_indrag="status_indrag" :grouplevel="item.cell"
                :devicelist="device_list" :current_show_id="current_show_id" :width="item.width || group.width"
                :datamap="item.datamap" :left="group.left || 0" :right="group.right || 0"
                :top="group.top ? group.top + index * (group.pad || 3) : 0"
                :bottom="group.bottom ? group.bottom - index * (group.pad || 3) : 0"></bridge>
      </div> -->
        backgroundImage: `url(${areaUrl})`,
        backgroundSize: 'cover',
        backgroundPosition: 'center',
        backgroundRepeat: 'no-repeat',
        top: `${position.top}px`,
        left: `${position.left}px`,
      }">
      <div v-for="(item, index) in elements" :key="index" class="grid-item bridge-items" :style="{
        width: elementWidth + 'rem',
        height: elementHeight + 'rem',
        top: `${item.y * elementHeight}rem`,
        left: `${item.x * elementWidth}rem`
        top: `${item.row * elementHeight}rem`,
        left: `${item.cell * elementWidth}rem`
      }">
        <!-- 每个元素的内容可以放在这里 -->
@@ -51,17 +40,22 @@
              (!item?.deviceInfo || !item?.deviceInfo?.id)? 'space-drag': '',
            ]"
        >
          <!-- <div v-show="item.deviceInfo &&  item.deviceInfo?.networkPort" -->
           <div 
            class="space-text" @dragstart="dragstart($event, index)" @dragend="dragend($event, index)"
              class="space-text"
              :class="[
                item?.deviceInfo?.statusInt == 2 ||
                item?.deviceInfo?.statusInt == 3 ||
                item?.deviceInfo?.statusInt == 4? 'space-text-red' : '',
                item?.deviceInfo?.statusInt == 1 ? 'space-text-yellow' : '',
              ]"
              @dragstart="dragstart($event, index)" @dragend="dragend($event, index)"
            @drop="handleDrop($event, index)" @dragover="handleDragOver($event)" draggable="true"
            @click="showDeviceInfo(index,item,$event)"
            >
            {{ item.deviceInfo?.networkPort }}
            <device-info v-show="selectedIndex === index " :show_info="show_device_info"
              :device_info="cur_device_info" @toSwitchInfo="toSwitchInfo"
              :device_info="cur_device_info" @toSwitchInfo="toSwitchInfo" @statusPort="statusPort"
               @delPort="delPort"
              ></device-info>
          </div>
        </div>
@@ -83,7 +77,7 @@
      <div class="img-button"></div>
    </div>
    <equ-add-form ref="equAddForm" :code="code" :areas="areas" :init_device_list="device_list"
      @update="update_map"></equ-add-form>
      @update="update_device_info" :cur_item="cur_item"></equ-add-form>
    <server-info v-if="!hideServe" :serve_info="serve_info" :serve_select="serve_select" :code="code"></server-info>
    <div class="back-button-left-bottom" @click="backToTop">返回</div>
@@ -97,6 +91,8 @@
import equAddForm from "@/components/equ-add-form.vue";
import deviceInfo from "@/components/device-info";
import A27 from '@/assets/screen/screen5/svgs3d/A27.svg'
import {
  getAreaServeInfo,
  getFaultInfo,
@@ -105,6 +101,7 @@
  getBridgeInfos,
  delport,
  statusPort,
  getAreaModuleBycode,
} from "@/api/area";
import { getAreaTjData } from "@/api/area";
@@ -195,6 +192,7 @@
      first_query_ip: true,
      totalElements: 1000, // 元素总数
      areaUrl: A27, // 区域背景图
      elements: [], // 初始化 elements 数据为空数组
      isDragging: false,
      dragSource: null, // 当前被拖拽的元素
@@ -202,7 +200,14 @@
      show_device_info: false, // 展示设备信息
      selectedIndex: null,
      cur_device_info: null,  // 当前的设备信息
      cur_item:null,// 当前的element
      offsetX: 0, // 鼠标点击时相对元素的 X 偏移量
      offsetY: 0, // 鼠标点击时相对元素的 Y 偏移量
      position: {
        top: 100, // 元素初始位置
        left: 100, // 元素初始位置
      },
    };
  },
  computed: {
@@ -223,7 +228,7 @@
  },
  created() {
    var zoom = this.$route.query.zoom;
    console.log(this.$route, this.$router);
    // console.log(this.$route, this.$router);
    if (zoom) {
      this.zoom_main = parseFloat(zoom);
    }
@@ -233,28 +238,28 @@
    this.screen_height = parseFloat(this.screen_height) * this.zoom;
  },
  async mounted() {
    console.log("main-container1,mounted");
    // console.log("main-container1,mounted");
    const content = document.getElementById("content");
    content.addEventListener("wheel", this.handleWheel);
    //获取到此区域的全部信息
    this.device_list = [];
    if (this.code) {
      // var re = await getDeviceList(this.code);
      // console.log("re", re);
      // this.device_list = re.switchDetialInfos || [];
      // await this.init_data();
      this.update_map();
      // this.update_map();
    }
    getAreaTjData().then((res) => {
      // console.log('areas',res.switchAreaInfo || [])
      this.areas = res.switchAreaInfo || [];
    });
    if(this.code){
       // 获取当前页面的背景图和数量
      this.initArea();
    // 根据屏幕初始化格子
    this.initializeElements(); // 在组件加载时初始化 elements
    // 初始化设备信息
    this.handleBindElementsItems()
    }
    // this.handleBindElementsItemsTest()
  },
  destroyed() {
    const content = document.getElementById("content");
@@ -262,16 +267,28 @@
    this.stopScrolling();
  },
  methods: {
    // 获取区域的背景图和数量
    async initArea(){
      const areaInfo = await getAreaModuleBycode(this.code)
      if(areaInfo&&areaInfo.areaModuleItems){
        let areaModuleItems=areaInfo.areaModuleItems
        this.totalElements = areaModuleItems.areaConfigNum === 0 ? 1000 : areaModuleItems.areaConfigNum;
        this.areaUrl =areaModuleItems.url
      }
    },
    initializeElements() {
      const elements = [];
      for (let i = 0; i < this.totalElements; i++) {
        const x = i % this.gridDimensions.columns;
        const y = Math.floor(i / this.gridDimensions.columns);
        const cell = i % this.gridDimensions.columns;
        const row = Math.floor(i / this.gridDimensions.columns);
        const isPlaceholder = false
        const name = x + "-" + y
        const name = row + "-" + cell
        // 绑定设备信息
        const deviceInfo = {}
        elements.push({ x, y, isPlaceholder, name, deviceInfo });
        elements.push({ row, cell, isPlaceholder, name, deviceInfo });
      }
      // 判断最后一行是否需要补齐
@@ -279,62 +296,176 @@
      if (remainder !== 0) {
        const placeholdersNeeded = this.gridDimensions.columns - remainder;
        for (let i = 0; i < placeholdersNeeded; i++) {
          const x = remainder + i;
          const y = Math.floor(this.totalElements / this.gridDimensions.columns);
          const cell = remainder + i;
          const row = Math.floor(this.totalElements / this.gridDimensions.columns);
          const isPlaceholder = false
          const name = x + "-" + y
          const name = row + "-" + cell
          // 绑定设备信息
          const deviceInfo = {}
          elements.push({ x, y, isPlaceholder, name, deviceInfo });
          elements.push({ row, cell, isPlaceholder, name, deviceInfo });
        }
      }
      // TODO 遍历elements给每个elements复制index,为当前的遍历的索引
      // 遍历 elements 添加 index 属性
      elements.forEach((element, index) => {
        element.index = index;
      });
      this.elements = elements; // 赋值给 data 中的 elements
    },
    // 根据元素的行列绑定元素信息
    async handleBindElementsItems() {
      const deviceInfoList = await getDeviceList(this.code)
      // 所有的格子信息
      console.log("所有的格子信息")
      console.log(this.elements)
      // 所有的设备信息
      console.log("所有的设备信息")
      console.log(deviceInfoList.switchDetialInfos)
      // 遍历 switchDetialInfos,构造 Map
      const switchDetailInfosMap = new Map();
      const switchDetialInfos = deviceInfoList.switchDetialInfos
      let deviceInfoList = await getDeviceList(this.code);
      // 获取 switchDetialInfos
      let switchDetialInfos = deviceInfoList.switchDetialInfos;
      console.log("所有的数量:"+this.totalElements)
      console.log("switchDetialInfos")
      console.log(switchDetialInfos)
      // 用于存放无效的设备信息
      let invalidSwitchDetails = [];
      // 用于存放重复 key 的设备信息
      let duplicateSwitchDetails = [];
      // 用于存放 areaRow 或 areaCell 为 -1 的设备信息
      let filteredSwitchDetails = [];
      // 创建一个 Map 来存储有效的设备信息
      let switchDetailInfosMap = new Map();
      // 遍历 switchDetialInfos
      switchDetialInfos.forEach((info) => {
        const key = `${info.areaRow}-${info.areaCell}`;
        // 直接将单个对象作为值放入 Map
        switchDetailInfosMap.set(key, info);
      });
        let { areaRow, areaCell } = info;
      console.log("设备信息转换后的 Map");
      console.log(switchDetailInfosMap);
        // 检查是否为无效值:""(空字符串)、undefined、null、-1
        if ([null, undefined, "", -1].includes(areaRow) || [null, undefined, "", -1].includes(areaCell)) {
          invalidSwitchDetails.push(info);
          return; // 跳过后续逻辑
        }
      // 遍历 elements,将匹配的设备信息添加到每个元素的 deviceInfo 属性
      this.elements.forEach((element) => {
        const key = `${element.y}-${element.x}`; // 使用元素的 y 和 x 构造 key
        const deviceInfo = switchDetailInfosMap.get(key); // 从 Map 中查找设备信息
        if (deviceInfo) {
          // 如果找到设备信息,存放到 element 的 deviceInfo 属性
          element.deviceInfo = deviceInfo;
          element.isPlaceholder = true
        // 检查是否包含 -1,记录到 filteredSwitchDetails
        if (areaRow == -1 || areaCell == -1) {
          filteredSwitchDetails.push(info);
          return; // 跳过后续逻辑
        }
        // 构造唯一 key
        let key = `${areaRow}-${areaCell}`;
        console.log(key)
        // 检查 key 是否已经存在
        if (switchDetailInfosMap.has(key)) {
          // 如果存在,将当前 info 添加到重复数组中
          duplicateSwitchDetails.push(info);
        } else {
          // 如果未找到,则清空或设置默认值
          element.deviceInfo = null;
          element.isPlaceholder = false
          // 如果不存在,将 info 存入 Map
          switchDetailInfosMap.set(key, info);
        }
      });
      console.log("总数量:",switchDetialInfos.length)
      console.log("无效的设备信息:", invalidSwitchDetails);
      console.log("包含 -1 的设备信息:", filteredSwitchDetails);
      console.log("重复的设备信息:", duplicateSwitchDetails);
      console.log("设备信息转换后的 Map:", switchDetailInfosMap);
      // Step 1: 将 this.elements 转换为 Map,方便快速查找
      // let elementsMap = new Map(
      //   this.elements.map((element) => [`${element.row}-${element.cell}`, element])
      // );
      // // Step 2: 遍历 switchDetailInfosMap,直接匹配 elementsMap 中的 key
      // switchDetailInfosMap.forEach((info, key) => {
      //   // 在 elementsMap 中查找匹配的元素
      //   let element = elementsMap.get(key);
      //   if (element) {
      //     // 如果找到匹配的元素,更新其信息
      //     element.deviceInfo = info;
      //     element.isPlaceholder = true;
      //   }
      // });
      // 遍历 elements,将匹配的设备信息绑定到对应的元素
      this.elements.forEach((element) => {
        let key = `${element.row}-${element.cell}`; // 使用元素的 row 和 cell 构造 key
        let deviceInfo = switchDetailInfosMap.get(key); // 从 Map 中查找设备信息
        if (deviceInfo) {
          // 如果找到设备信息,存放到 element 的 deviceInfo 属性
          element.deviceInfo = deviceInfo;
          element.isPlaceholder = true;
        } else {
          // 如果未找到,则清空或设置默认值
          element.deviceInfo = null;
          element.isPlaceholder = false;
        }
      });
      // 合并无效和重复的设备信息数组,并倒序 filteredSwitchDetails
      let allDeviceDetails = [...invalidSwitchDetails, ...duplicateSwitchDetails,...filteredSwitchDetails];
      console.log("allDeviceDetails:", allDeviceDetails);
      // 遍历 elements,并查找 deviceInfo 为空的元素
      let emptyDeviceInfoElements = [];
      // 创建 elements 的浅拷贝,并倒序遍历
      const reversedElements = [...this.elements].reverse();
      // 遍历 reversedElements,并查找 deviceInfo 为空的元素
      reversedElements.forEach((element) => {
        if (!element.deviceInfo) {
          // 记录所有 deviceInfo 为空的元素
          emptyDeviceInfoElements.push(element);
        }
      });
      // 确保空的 deviceInfo 元素数组的长度与 allDeviceDetails 数组的长度一致
      let totalDevices = Math.min(emptyDeviceInfoElements.length, allDeviceDetails.length);
      // 动态为这些元素赋值设备信息
      for (let i = 0; i < totalDevices; i++) {
        const device = allDeviceDetails[i] || {}; // 防止越界
        const element = emptyDeviceInfoElements[i];
        device.areaRow = element.row;
        device.areaCell = element.cell;
        element.deviceInfo = device;
        element.isPlaceholder = true; // 设置占位符
        // 根据索引更新原数组的元素
        const originalIndex = this.elements.findIndex((el) => el.row === element.row && el.cell === element.cell);
        if (originalIndex !== -1) {
          this.elements[originalIndex] = element;
        }
      }
    },
    async handleBindElementsItemsTest() {
      const deviceInfoList = await getDeviceList(this.code)
      const switchDetialInfos = deviceInfoList.switchDetialInfos
      // const evenIndexes = this.elements.filter((_, index) => index % 2 === 0);
      const evenIndexes = this.elements.filter(element => element.cell % 2 == 0);
      evenIndexes.forEach((element, index) => {
        element.deviceInfo = switchDetialInfos[index] || null;
        // element.isPlaceholder = !!switchDetialInfos[index];
        element.isPlaceholder=true;
      });
      console.log("所有布局元素")
      console.log(this.elements)
    },
    handleItemClick(item) {
      this.isDragging = false;
      item.deviceInfo = null;
      this.$set(item, 'isPlaceholder', true)
    },
    handleItemClickCancel(item) {
      this.isDragging = false;
      // 这里的取消操作需要判断当前的元素是不是空的
      if(item?.deviceInfo?.id){
        // this.$message('空设备才可双击删除!');
@@ -347,6 +478,7 @@
    toSwitchInfo(info) {
      this.isDragging = false;
      this.showServe(info);
    },
    async statusPort(info) {
@@ -364,7 +496,12 @@
      this.$modal.closeLoading();
      this.update_map();
       // 根据屏幕初始化格子
      this.initializeElements(); // 在组件加载时初始化 elements
      // 初始化设备信息
      this.handleBindElementsItems()
      // this.update_map();
    },
    async delPort(info) {
@@ -391,6 +528,14 @@
      }
      this.$router.push({ path: "/area-all" });
    },
    async update_device_info() {
       // 根据屏幕初始化格子
        this.initializeElements(); // 在组件加载时初始化 elements
        // 初始化设备信息
        this.handleBindElementsItems()
    },
    async update_map() {
      this.$modal.loading("加载中");
      var re = await getDeviceList(this.code);
@@ -430,138 +575,39 @@
      console.log("this.$refs.equAddForm", this.$refs.equAddForm);
      this.$refs.equAddForm && this.$refs.equAddForm.openform(locInfo);
    },
    async showServeInfo(info) {
      
      //展示交换机全部端口
      console.log("showServeInfo", info);
      //弹出框展示全部端口,并且每个端口的情况
      //获取一下信息
      this.$modal.loading("加载中");
      const res = await getDeviceList(this.code, info.cabinetName);
      this.$modal.closeLoading();
      console.log("serveinfo", res);
      // this.activateSwitchPorts = res.switchDetialInfos || [];
      this.activateSwitchPorts = {};
      //分两行,每行24个
      this.switchAllDetialInfos = res.switchAllDetialInfos || []
      var activaePorts = {};
      if (res.switchDetialInfos) {
        for (var item of res.switchDetialInfos) {
          if (item.port) activaePorts[item.port] = item;
        }
      }
      console.log("activaePorts", activaePorts);
      for (var i = 0; i <= 47; i++) {
        var level = "" + parseInt(i / 24);
        if (!this.activateSwitchPorts["" + level]) {
          this.activateSwitchPorts["" + level] = [];
        }
        this.activateSwitchPorts["" + level].push({
          index: "" + (i + 1),
          name: "",
          info: activaePorts["" + (i + 1)] || undefined,
        });
      }
      // console.log("this.activateSwitchPorts", this.activateSwitchPorts);
      this.dialog_activateSwitchPorts = true;
    },
    closeself() {
      console.log("closeself parent");
      this.chartclose = true;
    },
    update_status_indrag(result, currentid) {
      this.status_indrag = result;
      this.current_drag_index = currentid;
    },
    refresh_canvas() {
      //根据缩放比,视觉角度,来做渲染?,或者说,最简单的,直接都展示出来,缩放下面的?然后超出的不展示即可?
    },
    handleMouseMove(event) {
      if (this.mouse_click) {
        // console.log("handleMouseMove", event);
        //记录坐标,支持实时的?
        if (this.mouse_offset_last) {
          // this.tleft += 20 - this.mouse_offset_last.offsetX
          var offsetx = event.clientX - this.mouse_offset_last.clientX;
          var offsety = event.clientY - this.mouse_offset_last.clientY;
          // console.log("offset0", offsetx, offsety);
          var soffsetx = offsetx > 0 ? offsetx : -offsetx;
          var soffsety = offsety > 0 ? offsety : -offsety;
          if (soffsety >= soffsetx) {
            offsetx = 0;
          } else {
            offsety = 0;
          }
          // console.log("offsetx", offsetx, offsety);
          // this.tleft += offset * 0.1;
          // this.cal_offset_x += offset;
          // console.log('offset', event.offsetX - this.mouse_offset_last.offsetX)
          if (event.target.id == "content") {
            //让看板内部有偏移量
            if (offsetx != 0) {
              if (offsetx > 0) {
                this.container_offset_left +=
                  this.base_move_offset * this.scale_container;
              } else {
                this.container_offset_left -=
                  this.base_move_offset * this.scale_container;
              }
            }
            if (offsety != 0) {
              if (offsety > 0) {
                console.log("plus container_offset_top");
                this.container_offset_top +=
                  this.base_move_offset * this.scale_container;
              } else {
                console.log("mul container_offset_top");
                this.container_offset_top -=
                  this.base_move_offset * this.scale_container;
              }
            }
          }
        }
        this.mouse_offset_last = event;
      }
    },
    handleMouseUp(event) {
      // console.log("handleMouseUp", event);
      if (this.mouse_click) {
        if (this.mouse_click.className == "equipment-item") {
          //说明是转移视角的
          //可能就是设备的
          //直接修改坐标就行了
          //计算鼠标偏移量,然后转换为屏幕坐标,再转换为显示单位坐标,同时弹出提示?是否要更改吧,更改就调用接口
          if (
            this.mouse_offset_last &&
            (this.cal_offset_x || this.cal_offset_y)
          ) {
            console.log("update?", this.tleft);
            alert("是否要修改设备坐标");
          }
        } else {
        }
      }
      this.mouse_click = undefined;
      this.mouse_offset_last = undefined;
    },
      // 鼠标按下事件
    handleMouseDown(event) {
      if (event.target.className.indexOf("equipment-item") >= 0) {
      } else if (event.target.id == "content") {
        this.mouse_click = event.target;
      this.isDragging = true;
      this.offsetX = event.clientX - this.position.left;
      this.offsetY = event.clientY - this.position.top;
      document.addEventListener('mousemove', this.handleMouseMove);
      document.addEventListener('mouseup', this.handleMouseUp);
      document.body.style.cursor = 'grabbing'; // 改变光标为抓取状态
    },
    // 鼠标移动事件
    handleMouseMove(event) {
      if (this.isDragging) {
        this.position.left = event.clientX - this.offsetX;
        this.position.top = event.clientY - this.offsetY;
      }
    },
    handleMouseLeave(event) {
      this.mouse_click = undefined;
      this.mouse_offset_last = undefined;
    // 鼠标松开事件
    handleMouseUp() {
      if (this.isDragging) {
        this.isDragging = false;
        document.removeEventListener('mousemove', this.handleMouseMove);
        document.removeEventListener('mouseup', this.handleMouseUp);
        document.body.style.cursor = 'grab'; // 改变光标为抓取状态
      }
    },
    handleWheel(event) {
      event.preventDefault();
@@ -581,8 +627,12 @@
        this.container_offset_left = 0;
        this.container_offset_top = 0;
      }
      console.log("滚轮的缩放比")
      console.log(this.scale_container)
    },
    dragstart(e, index) {
      this.isDragging = false;
      console.log(e);
      this.dragSource = index; // 记录拖拽的源元素
      console.log("start", e);
@@ -591,62 +641,16 @@
    },
    // 拖拽完成事件
    async dragend(e, index) {
      this.isDragging = false;
      //确定是否需要更新
      let that = this;
      console.log("拖拽事件完成", index)
      console.log("拖拽目标Id:", e.target.id)
      return;
      var dto = this.device_list_map[e.target.id];
      that.$modal
        .confirm(
          "是否确定修改坐标,设备名:" + dto.switchName + "/" + dto.networkPort
        )
        .then(async (res) => {
          that.$modal.loading();
          console.log("end", e);
          console.log(e);
          that.cal_offset_x = e.clientX - that.startclientX; // 计算偏移量
          that.cal_offset_y = e.clientY - that.startclientY;
          var rawx = that.device_list_map[e.target.id].currentX;
          var rawy = that.device_list_map[e.target.id].currentY;
          that.device_list_map[e.target.id].currentX =
            parseFloat(that.device_list_map[e.target.id].currentX) +
            parseFloat(
              (that.cal_offset_x / that.html_base) * (1 / that.scale_container)
            ); // 实现拖拽元素随偏移量移动
          that.device_list_map[e.target.id].currentY =
            parseFloat(that.device_list_map[e.target.id].currentY) +
            parseFloat(
              (that.cal_offset_y / that.html_base) * (1 / that.scale_container)
            );
          // this.elTop += this.cal_offset_y;
          console.log("end drag2", that.device_list_map[e.target.id].currentX);
          //更新坐标信息,并保存
          var json = {
            id: dto.id.replace("content_", ""),
            operateType: 1,
            operateTime: new Date(),
            moveBeforeX: rawx,
            moveBeforeY: rawy,
            currentX: that.device_list_map[e.target.id].currentX,
            currentY: that.device_list_map[e.target.id].currentY,
          };
          const data = await updateDevicePosition(json);
          that.$modal.closeLoading();
          console.log("updateDevicePosition", data);
        })
        .catch((e) => {
        })
        .finally(() => {
        });
    },
    /**两个元素交换位置 */
    handleDrop(e, targetIndex) {
      this.isDragging = false;
      console.log("handleDrop")
      console.log(targetIndex)
      
@@ -656,6 +660,8 @@
      if (sourceIndex !== targetIndex &&(this.elements[sourceIndex].deviceInfo||this.elements[targetIndex].deviceInfo)) {
        const sourceDeviceInfo = this.elements[sourceIndex].deviceInfo;
        const targetDeviceInfo = this.elements[targetIndex].deviceInfo;
        const sourceElement=this.elements[sourceIndex]
        const targetElement=this.elements[targetIndex]
        let sourceNetworkPort="指定位置"
        if(sourceDeviceInfo?.networkPort){
          sourceNetworkPort=sourceDeviceInfo?.networkPort
@@ -675,9 +681,8 @@
        )
        .then(async (res) => { 
          
          this.elements[sourceIndex].deviceInfo = targetDeviceInfo
          this.elements[targetIndex].deviceInfo = sourceDeviceInfo
            // this.elements[sourceIndex].deviceInfo = targetDeviceInfo
            // this.elements[targetIndex].deviceInfo = sourceDeviceInfo
          if(this.elements[sourceIndex].deviceInfo==null){
            this.elements[sourceIndex].isPlaceholder=false;            
@@ -688,25 +693,50 @@
          }
          that.$modal.loading();
          var json = {
            let json;
            console.log()
            if (type) {
              // 交换
              json = {
              id: sourceDeviceInfo.id,
              operateType: 1,
                operateType: 3,
              operateTime: new Date(),
              networkPort: sourceDeviceInfo.networkPort,
              areaCell:this.elements[sourceIndex].x,
              areaRow:this.elements[sourceIndex].y,
              areaCellTarget:this.elements[targetIndex].x,
              areaRowTarget:this.elements[targetIndex].y,
                changeId:targetDeviceInfo?.id,
                changeAreaRow: targetElement.row,
                changeAreaCell: targetElement.cell,
                deviceInfo: {
                  areaRow: sourceElement.row,
                  areaCell:sourceElement.cell,
                  areaCode:this.code
                },
            };
            if (targetDeviceInfo?.id) {
              json["changeId"] = targetDeviceInfo?.id;
              json["operateType"] = 3;
            } else {
              // 移动
              const { id, networkPort } = sourceDeviceInfo ? sourceDeviceInfo : targetDeviceInfo;
              const { row, cell } = sourceDeviceInfo ? targetElement : sourceElement;
              json = {
                id: id,
                operateType: 1,
                operateTime: new Date(),
                networkPort: networkPort,
                deviceInfo: {
                  areaRow: row,
                  areaCell: cell,
                  areaCode:this.code
                },
              };
            }
          const data = await updateDevicePosition(json);
          that.$modal.closeLoading();
          if (data) {
              this.$message.success(`${targetid ? "交换" : "移动"}成功`);
              this.$message.success(`${type ? "交换" : "移动"}成功`);
          }
            // 根据屏幕初始化格子
@@ -715,21 +745,28 @@
            this.handleBindElementsItems()
        })
        .catch((e) => { })
          .catch((e) => {
            console.log(e);
           })
        .finally(() => { });
      
      }
    },
    handleDragOver(e) {
      this.isDragging = false;
      e.preventDefault();
    },
    // 点击增加
    handleClickToAddItem(index,item){
      debugger;
      // this.cur_device_info = item.deviceInfo
      // this.cur_device_info.areaRow=item.row
      // this.cur_device_info.areaCell=item.cell
      this.cur_item=item
      // 如果存在设备的话则直接返回
      if(item?.deviceInfo?.id) return;
      this.$refs.equAddForm && this.$refs.equAddForm.openform();
@@ -740,7 +777,6 @@
      var { data } = await getBridgeInfos(this.code);
      this.$modal.closeLoading();
      var arr = (data && data) || [];
      console.log("arr", arr);
      var currentareaconfig = mapdata[this.code] || {};
      this.bridge_infos = {};
@@ -797,12 +833,12 @@
          cells: item.areaCellRow || [],
          code: item.areaIndex,
        };
        console.log("bridge_infos", this.bridge_infos);
        console.log(
          "currentareaconfig",
          currentareaconfig[item.areaIndex],
          currentareaconfig["pad"]
        );
        // console.log("bridge_infos", this.bridge_infos);
        // console.log(
        //   "currentareaconfig",
        //   currentareaconfig[item.areaIndex],
        //   currentareaconfig["pad"]
        // );
        if (currentareaconfig["pad"]) {
          this.bridge_infos[item.areaIndex]["pad"] = currentareaconfig["pad"];
        }
@@ -860,10 +896,17 @@
      this.$modal.closeLoading();
    },
    showDeviceInfo(index, item,event) {
      this.isDragging = false;
      event.stopPropagation(); // 阻止事件冒泡
      this.selectedIndex = index
      this.show_device_info = !this.show_device_info
      this.cur_device_info = item.deviceInfo
      // 如果点击的是同一个元素,则切换显示状态
      if (this.selectedIndex === index) {
        this.show_device_info = !this.show_device_info;
      } else {
        // 切换到新元素,自动关闭之前的
        this.selectedIndex = index;
        this.show_device_info = true;
        this.cur_device_info = item.deviceInfo;
      }
    },
  },
};
@@ -1083,6 +1126,7 @@
  position: absolute;
  box-sizing: border-box;
  /* border: 1px solid #ccc; 可选样式,便于查看布局 */
  border: 1px solid #ccc;
  display: flex;
  justify-content: center;
  align-items: center;
src/views/screen1/itm-map-plant-board.vue
@@ -1,5 +1,5 @@
<template>
  <div style="position: relative;" class="itm-map-vr" @contextmenu="showMenu($event)"
  <div style="position: relative;" class="itm-map-vr" @contextmenu="showMenu($event)" ref="targetDiv"
    :style="{
        background: plantBoardFlag ? 'linear-gradient(-90deg, rgba(0, 0, 0, 0.1) 1px, transparent 1px) 0% 0% / 20px 20px, linear-gradient(rgba(0, 0, 0, 0.1) 1px, transparent 1px) 0% 0% / 20px 20px' : ''
      }" 
@@ -203,6 +203,8 @@
      areaVisible:false,
      areaPosition: { x: 0, y: 0 },
      mouseX:0,
      mouseY:0,
    };
  },
@@ -210,6 +212,11 @@
  mounted() {
    document.addEventListener("click", this.hideMenu);
    this.getAreaItemList();
    // document.addEventListener("mousemove", (event) => {
    //    this.mouseX = event.offsetX;
    //    this.mouseY = event.offsetY;
    //   console.log(`Mouse Position: X=${this.mouseX}, Y=${this.mouseY}`);
    // });
  },
  beforeUnmount() {
    document.removeEventListener("click", this.hideMenu);
@@ -317,6 +324,8 @@
    },
    showMenu(event) {
      event.preventDefault();
      // this.menuPosition = { x: this.mouseX, y: this.mouseY};
      // this.menuPosition = { x: event.offsetX, y: event.offsetY};
      this.menuPosition = { x: event.clientX, y: event.clientY };
      this.menuVisible = true;
      this.hideElementMenu()
src/views/screen1/itm.vue
@@ -137,7 +137,7 @@
              prop="cabinetName"
              label="Cabinet Name">
              <template slot-scope="scope">
                  <el-select v-model="scope.row.cabinetName" placeholder="请选择机柜" filterable clearable="" >
                  <el-select v-model="scope.row.cabinetName" placeholder="请选择机柜" filterable clearable>
                    <el-option
                      v-for="item in cabinetList"
                      :key="item.id"
@@ -153,7 +153,7 @@
              prop="areaCode"
              label="Area Code">
              <template slot-scope="scope">
                  <el-select v-model="scope.row.areaCode" placeholder="请选择区域" filterable clearable="" >
                  <el-select v-model="scope.row.areaCode" placeholder="请选择区域" filterable clearable>
                    <el-option
                      v-for="item in areaList"
                      :key="item.id"