2 Revize 6605d29467 ... 210e612bbe

Autor SHA1 Zpráva Datum
  houzekong 210e612bbe [Mod 0000] 过渡页面支持全局矿井联动 před 1 měsícem
  houzekong be6d203bc0 [Feat 0000] 地图管理相关功能改版 před 1 měsícem

+ 2 - 2
src/layouts/default/feature/SimpleMap.vue

@@ -8,6 +8,7 @@
       v-model:value="fileId"
       :options="fileOptions"
       :fieldNames="{ label: 'fileName', value: 'wjId' }"
+      :style="{ minWidth: '200px' }"
       @change="toggleCADMap(true)"
     ></a-select>
   </div>
@@ -269,7 +270,7 @@
         }
 
         const [m, res] = await Promise.all([
-          initMap2d(mapContainer.value!, { vjId: fileId.value, style: { backcolor: 0xe6f3ff } }),
+          initMap2d(mapContainer.value!, { wjId: fileId.value, style: { backcolor: 0xe6f3ff } }),
           props.slience
             ? Promise.resolve([])
             : getGoafList({
@@ -314,7 +315,6 @@
 
       // 不论是不是矿端,历史记录都是一样的,用户点击返回上一级都能正常返回
       historyStack.value = findPath(markerCollection, (n) => n.id === id) as any[];
-      console.log('debug findpath', markerCollection, historyStack.value);
 
       // 此外如果是非矿端那么模拟触发地图点击事件
       markerClickHandler();

+ 5 - 2
src/views/dashboard/Overhaul/index.vue

@@ -3,7 +3,7 @@
   <component :is="pageComponent"></component>
 </template>
 <script setup lang="ts">
-  import { Component, ref, watch } from 'vue';
+  import { ref, watch } from 'vue';
   import { useMineDepartmentStore } from '/@/store/modules/mine';
   import LeafPage from './components/LeafPage.vue';
   import RootPage from './components/RootPage.vue';
@@ -11,7 +11,7 @@
 
   const mineStore = useMineDepartmentStore();
 
-  const pageComponent = ref<Component>(Empty);
+  const pageComponent = ref<any>(Empty);
 
   watch(
     () => mineStore.getDepart,
@@ -23,6 +23,9 @@
       } else {
         pageComponent.value = RootPage;
       }
+    },
+    {
+      immediate: true,
     }
   );
 </script>

+ 18 - 30
src/views/system/cadFile/app.ts

@@ -1,5 +1,4 @@
 import vjmap, { Map, GeoBounds, GeoProjection, Service } from 'vjmap';
-import { env } from './env';
 // import { App, MapThreeLayer } from 'vjmap3d';
 import 'vjmap/dist/vjmap.min.css';
 import { useAppStore } from '/@/store/modules/app';
@@ -13,6 +12,7 @@ import { StatusColorEnum } from '/@/enums/jeecgEnum';
 // 图片路径
 import customImage from '/@/assets/icons/location-icon.svg';
 import customImage3D from '/@/assets/icons/location-icon3D.png';
+import { env } from './env';
 
 // ===================== 全局状态 =====================
 let map: Map | null = null;
@@ -24,18 +24,17 @@ let currentPopup: any = null;
 
 // ===================== 地图初始化部分 =====================
 // 初始化地图
-export const initMap2d = async (container: HTMLElement, config: { fileUrl?: string; style?: vjmap.IMapStyleParam; vjId?: string } = {}) => {
+export const initMap2d = async (container: HTMLElement, config: { fileUrl?: string; style?: vjmap.IMapStyleParam; wjId?: string } = {}) => {
   if (!container) {
     message.error('地图容器不存在!');
     throw new Error('地图容器不存在!');
   }
 
   const appStore = useAppStore();
-  // const httpDwgUrl = '/resource/test.dwg';
   const {
-    fileUrl = 'https://vjmap.com/static/assets/data/gym.dwg',
-    style = env.darkTheme ? vjmap.openMapDarkStyle() : vjmap.openMapLightStyle(),
-    vjId,
+    // fileUrl = 'https://vjmap.com/static/assets/data/gym.dwg',
+    style = vjmap.openMapLightStyle(),
+    wjId,
   } = config;
 
   container.style.background = 'transparent';
@@ -43,21 +42,12 @@ export const initMap2d = async (container: HTMLElement, config: { fileUrl?: stri
   container.style.height = `${get(container, 'parentElement.clientHeight', 0) / appStore.heightScale}px`;
 
   svc = new vjmap.Service(env.serviceUrl, env.accessToken);
-  if (env.workspace) svc.switchWorkspace(env.workspace);
 
   const res = await svc.openMap({
-    mapid: vjId || 'c56c59154345', // 地图ID,上传文件后获得的mapid
-    version: env.version,
-    cbInputPassword: () => {
-      return Promise.resolve('hllcad');
-    },
-    fileid: fileUrl,
-    // @ts-ignore
-    mapopenway: env.mapopenway || vjmap.MapOpenWay.GeomRender,
-    style: {
-      clipbounds: Math.pow(2, 6),
-      ...style,
-    },
+    mapid: wjId || 'c56c59154345', // 地图ID,上传文件后获得的mapid
+    fileid: wjId || 'c56c59154345', // 地图ID,上传文件后获得的mapid
+    mapopenway: vjmap.MapOpenWay.GeomRender,
+    style,
   });
 
   if (res.error) {
@@ -65,30 +55,28 @@ export const initMap2d = async (container: HTMLElement, config: { fileUrl?: stri
     console.error(res.error);
     // return null;
   }
+
   // 获取地图范围
   const mapExtent = GeoBounds.fromString(res.bounds);
+  // const mapExtent = GeoBounds.fromString(res.drawBounds);
   // 根据地图范围建立几何投影坐标系
   prj = new GeoProjection(mapExtent);
   // 地图对象
   map = new vjmap.Map({
     container, // DIV容器ID
-    style: svc.rasterStyle(), // 样式,这里是栅格样式
-    center: { lng: -0.9509370605581751, lat: -0.3509374623643043 }, // 设置地图中心点
-    // center: prj.toLngLat(mapExtent.center()), // 设置地图中心点
-    zoom: 11, // 设置地图缩放级别
-    // zoom: 1, // 设置地图缩放级别
-    pitch: 0,
-    trackResize: false,
+    style: svc.rasterStyle(),
+    center: prj.toLngLat(mapExtent.center()),
+    zoom: 8, // 设置地图缩放级别
+    // pitch: 0,
+    // trackResize: false,
     antialias: true, // 反锯齿
     renderWorldCopies: false, // 不显示多屏地图
   });
 
   // 关联服务对象和投影对象
   map.attach(svc, prj);
-  // map.on('click', (ev) => {
-  //   console.log(map?.getCenter());
-  //   console.log(map?.getZoom());
-  // });
+  map.fitMapBounds();
+
   await map.onLoad();
 
   return map;

+ 8 - 8
src/views/system/cadFile/cad.api.ts

@@ -6,19 +6,19 @@ export enum Api {
   getGoafData = '/province/device/getGoafData',
   getMineFileList = '/province/mineData/getMineFileList',
   uploadFile = '/sys/common/upload',
-  updateMineFile = 'province/mineData/updateMineFile',
-  addMineFile = 'province/mineData/addMineFile',
-  deleteMineFile = 'province/mineData/deleteMineFile',
+  updateMineFile = '/province/mineData/updateMineFile',
+  addMineFile = '/province/mineData/addMineFile',
+  deleteMineFile = '/province/mineData/deleteMineFile',
 }
 //查询密闭列表
 export function getGoafList(params: any) {
   return defHttp.post({ url: Api.getGoafList, params }, { joinParamsToUrl: true });
-};
+}
 
 // 更新密闭
 export function updatateGoaf(params: any) {
   return defHttp.post({ url: Api.updatateGoaf, params });
-};
+}
 // 查询密闭监测数据
 export function getGoafData(params: any) {
   return defHttp.post({ url: Api.getGoafData, params }, { joinParamsToUrl: true });
@@ -31,8 +31,8 @@ export function getMineFileList(params: any) {
 
 // cad文件上传
 export function uploadFile(params: any) {
-  return defHttp.post({ headers: { 'Content-Type': 'multipart/form-data' }, url: Api.uploadFile, params },{ isTransformResponse:false });
-};
+  return defHttp.post({ headers: { 'Content-Type': 'multipart/form-data' }, url: Api.uploadFile, params }, { isTransformResponse: false });
+}
 // 修改煤矿图纸信息
 export function updateMineFile(params: any) {
   return defHttp.post({ url: Api.updateMineFile, params });
@@ -43,5 +43,5 @@ export function addMineFile(params: any) {
 }
 
 export function deleteMineFile(params: any) {
-  return defHttp.post({ url: Api.deleteMineFile, params },{ joinParamsToUrl: true });
+  return defHttp.post({ url: Api.deleteMineFile, params }, { joinParamsToUrl: true });
 }

+ 34 - 1
src/views/system/cadFile/cad.data.ts

@@ -1,5 +1,6 @@
 import { BasicColumn } from '/@/components/Table';
 import { FormSchema } from '/@/components/Table';
+import { useMineDepartmentStore } from '/@/store/modules/mine';
 
 // 3. 生成动态表格列(接收动态状态映射)
 export function getColumns(): BasicColumn[] {
@@ -86,6 +87,29 @@ export const formSchema: FormSchema[] = [
       changeOnSelect: false,
     },
     required: true,
+    dynamicRules: () => {
+      //需要return
+      return [
+        {
+          //默认开启表单检验
+          required: true,
+          // value 当前手机号输入的值
+          validator: (_, value) => {
+            //需要return 一个Promise对象
+            const dept = useMineDepartmentStore().findDepartById(value);
+            return new Promise((resolve, reject) => {
+              if (!dept) {
+                reject('请选择部门');
+              }
+              if (!dept?.isLeaf) {
+                reject('请选择具体矿井');
+              }
+              resolve();
+            });
+          },
+        },
+      ];
+    },
   },
   {
     label: '文件名称',
@@ -96,7 +120,16 @@ export const formSchema: FormSchema[] = [
   {
     label: '文件类型',
     field: 'fileType',
-    component: 'Input',
+    component: 'Select',
+    componentProps: {
+      options: [
+        { label: '安全监控部署图', value: '安全监控部署图' },
+        { label: '通风系统图', value: '通风系统图' },
+        { label: '防灭火图', value: '防灭火图' },
+        { label: '人员位置监测系统图', value: '人员位置监测系统图' },
+        { label: '采掘工程平面图', value: '采掘工程平面图' },
+      ],
+    },
     required: true,
   },
   {

+ 11 - 1
src/views/system/cadFile/components/MapEditModal.vue

@@ -30,9 +30,12 @@
   import { BasicForm, useForm } from '/@/components/Form';
   import { BasicModal, useModalInner } from '/@/components/Modal';
   import vjmap from 'vjmap';
-  import { env } from '../env';
   import dayjs from 'dayjs';
   import { addMineFile, updateMineFile } from '../cad.api';
+  import { useMineDepartmentStore } from '/@/store/modules/mine';
+  import { env } from '../env';
+
+  const mineStore = useMineDepartmentStore();
 
   const emit = defineEmits(['success']);
 
@@ -50,10 +53,17 @@
 
   async function handleSubmit() {
     const formData = await validate();
+    const dept = mineStore.findDepartById(formData.mineCode);
+
+    if (!dept || !dept.isLeaf) {
+      message.info('请选择具体矿名');
+      throw Error('请选择具体矿名');
+    }
 
     setModalProps({ confirmLoading: true });
 
     formData.createTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
+    formData.mineCode = dept.fax;
 
     if (!formData.id) {
       await addMineFile(formData);

+ 82 - 0
src/views/system/cadFile/components/MapView.vue

@@ -0,0 +1,82 @@
+<template>
+  <div class="position-relative">
+    <div ref="map3dContainer"></div>
+    <!-- 操作按钮面板 -->
+    <div class="map-operation-panel">
+      <button @click="drawerVisible = true" class="btn">老空区永久密闭列表{{ drawerVisible }}</button>
+      <button @click="emit('close')" class="btn ml-5px">返回列表</button>
+    </div>
+
+    <SideDrawer v-model:open="drawerVisible" :mineCode="mineCode" :getContainer="() => map3dContainer" />
+  </div>
+</template>
+
+<script lang="ts" setup>
+  import { onMounted, onUnmounted, ref } from 'vue';
+  // 直接导入app.ts中导出的方法
+  import { initMap2d } from '../app';
+  // import { message } from 'ant-design-vue';
+  // 导入侧边弹框组件
+  import SideDrawer from './SideDrawer.vue';
+
+  const props = defineProps<{
+    mineCode: string;
+    wjId: string;
+  }>();
+
+  const emit = defineEmits(['close']);
+
+  // 定义弹框显隐状态
+  const drawerVisible = ref(false);
+  const map3dContainer = ref<HTMLElement>();
+
+  let map: any;
+
+  // 初始化地图(确保先加载地图,再调用其他方法)
+  onMounted(() => {
+    // nextTick(async () => {
+    initMap2d(map3dContainer.value!, {
+      wjId: props.wjId as string,
+    }).then((m) => (map = m));
+    // });
+  });
+
+  onUnmounted(() => {
+    map?.destory();
+  });
+</script>
+
+<style scoped>
+  #map3dContainer {
+    position: absolute;
+    background: transparent;
+    width: 100%;
+    height: 100%;
+    top: 0;
+    left: 0;
+  }
+
+  /* 操作面板样式 */
+  .map-operation-panel {
+    position: absolute;
+    top: 20px;
+    left: 20px;
+    z-index: 999;
+    display: flex;
+    gap: 8px;
+  }
+
+  .btn {
+    padding: 8px 12px;
+    background: #409eff;
+    color: #fff;
+    border: none;
+    border-radius: 4px;
+    cursor: pointer;
+    transition: background 0.2s;
+  }
+
+  .btn:hover {
+    background: #66b1ff;
+  }
+</style>

+ 363 - 0
src/views/system/cadFile/components/SideDrawer.txt

@@ -0,0 +1,363 @@
+<template>
+  <!-- 自定义左侧抽屉-->
+  <div class="custom-drawer" :class="{ 'custom-drawer-open': visible }">
+    <!-- 抽屉头部:标题 + 关闭按钮 -->
+    <div class="custom-drawer-header">
+      <span class="custom-drawer-title">老空区永久密闭管理</span>
+      <div @click="handleClose" class="close-btn"> X </div>
+    </div>
+
+    <!-- 抽屉内容区 -->
+    <div class="custom-drawer-body" v-if="visible">
+      <div class="drawer-content">
+        <!-- 搜索区域 -->
+        <!-- <div class="search-section">
+          <MineCascader
+            v-model:value="selectedMineId"
+            placeholder="请选择煤矿"
+            style="width: 60%; margin-right: 8px"
+            :syncToStore="false"
+            :initFromStore="false"
+            :showSearch="true"
+            :allowClear="true"
+            @change="handleMineChange"
+          />
+          <a-button type="primary" @click="handleGoafSearch" style="margin-right: 8px">
+            搜索
+          </a-button>
+          <a-button @click="handleRefresh">
+            刷新
+          </a-button>
+        </div> -->
+        <div class="search-section">
+          <a-input v-model:value="searchValue" placeholder="密闭位置" style="width: 60%; margin-right: 8px" />
+        </div>
+
+        <!-- 传感器数据表格 -->
+        <div class="table-section">
+          <a-table
+            :columns="columns"
+            :data-source="filteredDataWithStatus"
+            :pagination="pagination"
+            :row-key="(record) => record.id"
+            @change="handleTableChange"
+            :scroll="{ y: 'calc(100vh - 320px)' }"
+            size="middle"
+          >
+            <!-- 操作列自定义渲染 -->
+            <template #operation="{ record }">
+              <a-space>
+                <a-button v-if="!record.isPlaced" size="small" @click="handleDeploy(record)"> 布点 </a-button>
+                <a-button v-else size="small" danger @click="handleRemove(record)"> 移除 </a-button>
+              </a-space>
+            </template>
+          </a-table>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+  import { ref, computed, onMounted, watch } from 'vue';
+  import { message } from 'ant-design-vue';
+  import { bindPosition, removePosition, getMarkerStatusList, renderGoafMarkers } from '../app';
+  import { getGoafList } from '../cad.api';
+
+  interface Props {
+    visible: boolean;
+    mineCode: string;
+  }
+  const props = defineProps<Props>();
+  const emit = defineEmits<{
+    (e: 'update:visible', value: boolean): void;
+  }>();
+
+  // 响应式数据
+  const searchValue = ref('');
+  const pagination = ref({
+    current: 1,
+    pageSize: 10,
+    total: 0, // 初始化为0,由接口数据决定
+  });
+  const selectedMineId = ref('');
+  // 新增:存储接口返回的密闭数据
+  const goafList = ref<any[]>([]);
+
+  // 表格列配置 - 修复字段拼写错误(devicePos → devicePos)
+  const columns = [
+    {
+      title: '操作',
+      key: 'operation',
+      slots: { customRender: 'operation' },
+      width: 80,
+      fixed: 'left',
+    },
+    {
+      title: '密闭位置',
+      dataIndex: 'devicePos', // 修正拼写错误
+      key: 'devicePos',
+      ellipsis: true,
+      tooltip: true,
+    },
+  ];
+
+  // 表格数据过滤逻辑 - 核心修改:基于接口坐标判断isPlaced
+  const filteredDataWithStatus = computed(() => {
+    // 从接口返回的goafList过滤
+    let filteredData = goafList.value.filter((item) => {
+      // 密闭位置搜索匹配(兼容空值)
+      const isSearchMatch = searchValue.value ? (item.devicePos || '').includes(searchValue.value) : true;
+      return isSearchMatch;
+    });
+
+    // 关联标记状态 + 核心:优先判断接口返回的坐标
+    const placedMarkers = getMarkerStatusList() || [];
+    const dataWithStatus = filteredData.map((item) => {
+      // 判断接口坐标是否有效(非null/""且为数字)
+      const hasValidX = item.xcoordinate && !isNaN(Number(item.xcoordinate));
+      const hasValidY = item.ycoordinate && !isNaN(Number(item.ycoordinate));
+      // 兜底:本地标记是否存在(防止接口未同步的临时状态)
+      const matchedMarker = placedMarkers.find((marker) => marker.data?.id === item.id);
+
+      return {
+        ...item,
+        // 优先用接口坐标判断,无接口坐标时用本地标记
+        isPlaced: hasValidX && hasValidY,
+        sensorId: matchedMarker?.sensorId || item.id,
+      };
+    });
+
+    // 分页逻辑
+    const start = (pagination.value.current - 1) * pagination.value.pageSize;
+    const end = start + pagination.value.pageSize;
+    pagination.value.total = filteredData.length;
+    return dataWithStatus.slice(start, end);
+  });
+
+  // 关闭抽屉
+  const handleClose = () => emit('update:visible', false);
+
+  // 搜索方法
+  const handleGoafSearch = async () => {
+    // 校验:必须选择煤矿
+    if (!selectedMineId.value) {
+      message.warning('请先选择煤矿!');
+      return;
+    }
+
+    try {
+      // 调用接口
+      const res = await getGoafList({
+        order: 'desc',
+        mineCode: selectedMineId.value,
+      });
+      goafList.value = res || [];
+      pagination.value.current = 1; // 搜索后重置页码到第一页
+      renderGoafMarkers(goafList.value); // 渲染标记
+    } catch (error) {
+      goafList.value = [];
+      message.error(`查询失败:${(error as Error).message}`);
+      console.error('接口请求失败:', error);
+    }
+  };
+
+  // 刷新方法 - 优化:强制重新请求接口
+  const handleRefresh = async () => {
+    searchValue.value = '';
+    pagination.value.current = 1;
+    pagination.value = { ...pagination.value }; // 触发响应式更新
+
+    // 如果已选择煤矿,刷新时重新请求接口(保证数据最新)
+    if (selectedMineId.value) {
+      await handleGoafSearch();
+    } else {
+      goafList.value = []; // 未选煤矿则清空表格
+    }
+  };
+
+  // 表格分页变化
+  const handleTableChange = (pag: any) => {
+    pagination.value = { ...pagination.value, ...pag };
+  };
+
+  // 布点方法 - 优化:布点后主动刷新接口数据
+  const handleDeploy = async (record: any) => {
+    try {
+      const marker = await bindPosition({
+        id: record.id,
+        devicePos: record.devicePos,
+      });
+      if (!marker) {
+        message.warning('布点操作已取消');
+        return;
+      }
+      // 布点成功后刷新接口数据,保证按钮状态同步
+      await handleRefresh();
+    } catch (error) {
+      message.error(`布点失败:${(error as Error).message}`);
+      console.error('布点失败:', error);
+    }
+  };
+
+  // 移除后主动刷新接口数据
+  const handleRemove = async (record: any) => {
+    try {
+      const isSuccess = await removePosition(record.sensorId, record.id);
+      if (isSuccess) {
+        // 移除成功后刷新接口数据,保证按钮状态同步
+        await handleRefresh();
+      }
+    } catch (error) {
+      message.error(`移除失败:${(error as Error).message}`);
+      console.error('移除失败:', error);
+    }
+  };
+
+  // 煤矿选择变化
+  const handleMineChange = (mineId: string) => {
+    selectedMineId.value = mineId;
+  };
+
+  watch(
+    () => props.mineCode,
+    (newVal) => {
+      if (newVal) {
+        selectedMineId.value = newVal;
+      }
+    },
+    { immediate: true }
+  );
+
+  // 监听抽屉显隐:打开时刷新数据
+  watch(
+    () => props.visible,
+    async (isVisible) => {
+      if (isVisible) await handleRefresh(); // 异步数据加载
+    },
+    { immediate: true }
+  );
+
+  // 初始化:分页总数同步为接口数据量
+  onMounted(() => {
+    pagination.value.total = goafList.value.length;
+  });
+</script>
+
+<style scoped>
+  /* 自定义抽屉核心容器 */
+  .custom-drawer {
+    position: fixed;
+    top: 50px;
+    left: 30px;
+    z-index: 999;
+    width: 450px;
+    height: calc(100vh - 50px);
+    background: #ffffff;
+    box-shadow: 2px 0 12px rgba(0, 0, 0, 0.1);
+    transform: translateX(-100%);
+    transition: transform 0.3s cubic-bezier(0.2, 0, 0, 1);
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+  }
+
+  /* 抽屉打开状态 - 滑入动画 */
+  .custom-drawer-open {
+    transform: translateX(0);
+  }
+
+  /* 抽屉头部 */
+  .custom-drawer-header {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    color: #ffffff;
+    background-color: #2d4f82;
+    padding: 14px 20px;
+    flex-shrink: 0;
+  }
+
+  .custom-drawer-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #ffffff;
+    line-height: 1.5;
+  }
+
+  .close-btn {
+    font-size: 20px;
+    padding: 0;
+    height: 20px;
+    width: 20px;
+    margin-top: -10px;
+    cursor: pointer;
+  }
+
+  /* 抽屉内容区 */
+  .custom-drawer-body {
+    flex: 1;
+    overflow-y: auto;
+    padding: 0;
+  }
+
+  .drawer-content {
+    padding: 16px 20px;
+  }
+
+  /* 搜索区域布局 */
+  .search-section {
+    display: flex;
+    align-items: center;
+    margin-bottom: 16px;
+    width: 100%;
+  }
+
+  /* 下拉选择区域间距 */
+  .select-section {
+    margin-bottom: 16px;
+  }
+
+  /* 表格区域宽度适配 */
+  .table-section {
+    width: 100%;
+  }
+
+  /* 表格样式 */
+  :deep(.ant-table) {
+    font-size: 14px;
+  }
+
+  :deep(.ant-table-thead > tr > th) {
+    background: #fafafa;
+    font-weight: 600;
+    color: #000;
+    padding: 10px 12px;
+    border-bottom: 1px solid #f0f0f0;
+  }
+
+  :deep(.ant-table-tbody > tr > td) {
+    color: #000 !important;
+    font-family: Source Han Sans SC !important;
+    font-size: 16px !important;
+    font-weight: 400 !important;
+    letter-spacing: 0 !important;
+  }
+  :deep(.ant-table-tbody > .ant-table-row) {
+    &:hover {
+      background-color: #a4d3ee !important;
+    }
+  }
+  :deep(.ant-table-tbody > .ant-table-row > td) {
+    background-color: unset !important;
+    &:hover {
+      background-color: unset !important;
+    }
+  }
+
+  /* 分页样式 */
+  :deep(.ant-pagination) {
+    margin: 16px 0 0 0;
+    text-align: right;
+  }
+</style>

+ 94 - 199
src/views/system/cadFile/components/SideDrawer.vue

@@ -1,17 +1,29 @@
 <template>
   <!-- 自定义左侧抽屉-->
-  <div class="custom-drawer" :class="{ 'custom-drawer-open': visible }">
+  <Drawer
+    class="custom-drawer"
+    :open="open"
+    :closable="false"
+    :mask="true"
+    :maskClosable="false"
+    :maskStyle="{ background: 'transparent', pointerEvents: 'none' }"
+    placement="left"
+    :width="400"
+    :get-container="getContainer"
+    @update:open="emit('update:open', $event)"
+  >
     <!-- 抽屉头部:标题 + 关闭按钮 -->
-    <div class="custom-drawer-header">
-      <span class="custom-drawer-title">老空区永久密闭管理</span>
-      <div @click="handleClose" class="close-btn"> X </div>
-    </div>
-
-    <!-- 抽屉内容区 -->
-    <div class="custom-drawer-body" v-if="visible">
-      <div class="drawer-content">
-        <!-- 搜索区域 -->
-        <!-- <div class="search-section">
+    <template #title>
+      老空区永久密闭管理
+      <!-- <span class="custom-drawer-title"></span> -->
+    </template>
+    <template #extra>
+      <CloseOutlined class="cursor-pointer" @click="emit('update:open', false)" />
+    </template>
+
+    <div class="h-full">
+      <!-- 搜索区域 -->
+      <!-- <div class="search-section">
           <MineCascader
             v-model:value="selectedMineId"
             placeholder="请选择煤矿"
@@ -29,63 +41,64 @@
             刷新
           </a-button>
         </div> -->
-        <div class="search-section">
-          <a-input v-model:value="searchValue" placeholder="密闭位置" style="width: 60%; margin-right: 8px" />
-        </div>
+      <div class="mb-5px">
+        <a-input v-model:value="searchValue" placeholder="密闭位置" style="width: 60%; margin-right: 8px" />
+      </div>
 
-        <!-- 传感器数据表格 -->
-        <div class="table-section">
-          <a-table
-            :columns="columns"
-            :data-source="filteredDataWithStatus"
-            :pagination="pagination"
-            :row-key="(record) => record.id"
-            @change="handleTableChange"
-            :scroll="{ y: 'calc(100vh - 320px)' }"
-            size="middle"
-          >
-            <!-- 操作列自定义渲染 -->
-            <template #operation="{ record }">
-              <a-space>
-                <a-button v-if="!record.isPlaced" size="small" @click="handleDeploy(record)"> 布点 </a-button>
-                <a-button v-else size="small" danger @click="handleRemove(record)"> 移除 </a-button>
-              </a-space>
-            </template>
-          </a-table>
-        </div>
+      <!-- 传感器数据表格 -->
+      <div class="table-section">
+        <BasicTable
+          :columns="columns"
+          :data-source="filteredDataWithStatus"
+          :pagination="true"
+          :row-key="(record) => record.id"
+          :scroll="{ y: 'calc(100vh - 320px)' }"
+          size="middle"
+        >
+          <!-- 操作列自定义渲染 -->
+          <template #operation="{ record }">
+            <a-space>
+              <a-button v-if="!record.isPlaced" size="small" @click="handleDeploy(record)"> 布点 </a-button>
+              <a-button v-else size="small" danger @click="handleRemove(record)"> 移除 </a-button>
+            </a-space>
+          </template>
+        </BasicTable>
       </div>
     </div>
-  </div>
+  </Drawer>
 </template>
 
 <script lang="ts" setup>
-  import { ref, computed, onMounted, watch } from 'vue';
-  import { message } from 'ant-design-vue';
+  import { ref, computed, watch } from 'vue';
+  import { Drawer, message } from 'ant-design-vue';
+  import { BasicColumn, BasicTable } from '/@/components/Table';
   import { bindPosition, removePosition, getMarkerStatusList, renderGoafMarkers } from '../app';
   import { getGoafList } from '../cad.api';
+  import { CloseOutlined } from '@ant-design/icons-vue';
 
-  interface Props {
-    visible: boolean;
+  const props = defineProps<{
+    open: boolean;
     mineCode: string;
-  }
-  const props = defineProps<Props>();
+    getContainer?: any;
+  }>();
+
   const emit = defineEmits<{
-    (e: 'update:visible', value: boolean): void;
+    (e: 'update:open', value: boolean): void;
   }>();
 
   // 响应式数据
   const searchValue = ref('');
-  const pagination = ref({
-    current: 1,
-    pageSize: 10,
-    total: 0, // 初始化为0,由接口数据决定
-  });
-  const selectedMineId = ref('');
+  // const pagination = ref({
+  //   current: 1,
+  //   pageSize: 10,
+  //   total: 0, // 初始化为0,由接口数据决定
+  // });
+  const selectedMineId = ref(props.mineCode);
   // 新增:存储接口返回的密闭数据
   const goafList = ref<any[]>([]);
 
   // 表格列配置 - 修复字段拼写错误(devicePos → devicePos)
-  const columns = [
+  const columns: BasicColumn[] = [
     {
       title: '操作',
       key: 'operation',
@@ -98,7 +111,7 @@
       dataIndex: 'devicePos', // 修正拼写错误
       key: 'devicePos',
       ellipsis: true,
-      tooltip: true,
+      // tooltip: true,
     },
   ];
 
@@ -129,15 +142,13 @@
     });
 
     // 分页逻辑
-    const start = (pagination.value.current - 1) * pagination.value.pageSize;
-    const end = start + pagination.value.pageSize;
-    pagination.value.total = filteredData.length;
-    return dataWithStatus.slice(start, end);
+    // const start = (pagination.value.current - 1) * pagination.value.pageSize;
+    // const end = start + pagination.value.pageSize;
+    // pagination.value.total = filteredData.length;
+    // return dataWithStatus.slice(start, end);
+    return dataWithStatus;
   });
 
-  // 关闭抽屉
-  const handleClose = () => emit('update:visible', false);
-
   // 搜索方法
   const handleGoafSearch = async () => {
     // 校验:必须选择煤矿
@@ -153,7 +164,7 @@
         mineCode: selectedMineId.value,
       });
       goafList.value = res || [];
-      pagination.value.current = 1; // 搜索后重置页码到第一页
+      // pagination.value.current = 1; // 搜索后重置页码到第一页
       renderGoafMarkers(goafList.value); // 渲染标记
     } catch (error) {
       goafList.value = [];
@@ -165,8 +176,8 @@
   // 刷新方法 - 优化:强制重新请求接口
   const handleRefresh = async () => {
     searchValue.value = '';
-    pagination.value.current = 1;
-    pagination.value = { ...pagination.value }; // 触发响应式更新
+    // pagination.value.current = 1;
+    // pagination.value = { ...pagination.value }; // 触发响应式更新
 
     // 如果已选择煤矿,刷新时重新请求接口(保证数据最新)
     if (selectedMineId.value) {
@@ -177,9 +188,9 @@
   };
 
   // 表格分页变化
-  const handleTableChange = (pag: any) => {
-    pagination.value = { ...pagination.value, ...pag };
-  };
+  // const handleTableChange = (pag: any) => {
+  //   pagination.value = { ...pagination.value, ...pag };
+  // };
 
   // 布点方法 - 优化:布点后主动刷新接口数据
   const handleDeploy = async (record: any) => {
@@ -215,149 +226,33 @@
   };
 
   // 煤矿选择变化
-  const handleMineChange = (mineId: string) => {
-    selectedMineId.value = mineId;
-  };
-
-  watch(
-    () => props.mineCode,
-    (newVal) => {
-      if (newVal) {
-        selectedMineId.value = newVal;
-      }
-    },
-    { immediate: true }
-  );
+  // const handleMineChange = (mineId: string) => {
+  //   selectedMineId.value = mineId;
+  // };
+
+  // watch(
+  //   () => props.mineCode,
+  //   (newVal) => {
+  //     if (newVal) {
+  //       selectedMineId.value = newVal;
+  //     }
+  //   },
+  //   { immediate: true }
+  // );
 
   // 监听抽屉显隐:打开时刷新数据
   watch(
-    () => props.visible,
-    async (isVisible) => {
-      if (isVisible) await handleRefresh(); // 异步数据加载
+    () => props.open,
+    (v) => {
+      v && handleRefresh(); // 异步数据加载
     },
     { immediate: true }
   );
 
   // 初始化:分页总数同步为接口数据量
-  onMounted(() => {
-    pagination.value.total = goafList.value.length;
-  });
+  // onMounted(() => {
+  //   pagination.value.total = goafList.value.length;
+  // });
 </script>
 
-<style scoped>
-  /* 自定义抽屉核心容器 */
-  .custom-drawer {
-    position: fixed;
-    top: 50px;
-    left: 0;
-    z-index: 999;
-    width: 450px;
-    height: calc(100vh - 50px);
-    background: #ffffff;
-    box-shadow: 2px 0 12px rgba(0, 0, 0, 0.1);
-    transform: translateX(-100%);
-    transition: transform 0.3s cubic-bezier(0.2, 0, 0, 1);
-    display: flex;
-    flex-direction: column;
-    overflow: hidden;
-  }
-
-  /* 抽屉打开状态 - 滑入动画 */
-  .custom-drawer-open {
-    transform: translateX(0);
-  }
-
-  /* 抽屉头部 */
-  .custom-drawer-header {
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    color: #ffffff;
-    background-color: #2d4f82;
-    padding: 14px 20px;
-    flex-shrink: 0;
-  }
-
-  .custom-drawer-title {
-    font-size: 16px;
-    font-weight: 600;
-    color: #ffffff;
-    line-height: 1.5;
-  }
-
-  .close-btn {
-    font-size: 20px;
-    padding: 0;
-    height: 20px;
-    width: 20px;
-    margin-top: -10px;
-    cursor: pointer;
-  }
-
-  /* 抽屉内容区 */
-  .custom-drawer-body {
-    flex: 1;
-    overflow-y: auto;
-    padding: 0;
-  }
-
-  .drawer-content {
-    padding: 16px 20px;
-  }
-
-  /* 搜索区域布局 */
-  .search-section {
-    display: flex;
-    align-items: center;
-    margin-bottom: 16px;
-    width: 100%;
-  }
-
-  /* 下拉选择区域间距 */
-  .select-section {
-    margin-bottom: 16px;
-  }
-
-  /* 表格区域宽度适配 */
-  .table-section {
-    width: 100%;
-  }
-
-  /* 表格样式 */
-  :deep(.ant-table) {
-    font-size: 14px;
-  }
-
-  :deep(.ant-table-thead > tr > th) {
-    background: #fafafa;
-    font-weight: 600;
-    color: #000;
-    padding: 10px 12px;
-    border-bottom: 1px solid #f0f0f0;
-  }
-
-  :deep(.ant-table-tbody > tr > td) {
-    color: #000 !important;
-    font-family: Source Han Sans SC !important;
-    font-size: 16px !important;
-    font-weight: 400 !important;
-    letter-spacing: 0 !important;
-  }
-  :deep(.ant-table-tbody > .ant-table-row) {
-    &:hover {
-      background-color: #a4d3ee !important;
-    }
-  }
-  :deep(.ant-table-tbody > .ant-table-row > td) {
-    background-color: unset !important;
-    &:hover {
-      background-color: unset !important;
-    }
-  }
-
-  /* 分页样式 */
-  :deep(.ant-pagination) {
-    margin: 16px 0 0 0;
-    text-align: right;
-  }
-</style>
+<style scoped></style>

+ 24 - 21
src/views/system/cadFile/index.vue

@@ -1,12 +1,13 @@
 <!-- eslint-disable vue/multi-word-component-names -->
 <template>
-  <BasicTable @register="registerMapTable" :rowSelection="rowSelection">
+  <MapView v-if="showCAD" class="w-full h-full" v-bind="selected" @close="showCAD = false"></MapView>
+  <BasicTable v-else @register="registerMapTable" :rowSelection="rowSelection">
     <template #resetBefore>
       <!-- <a-button type="default" class="ml-8px" preIcon="mdi:download" @click="onExportXls"> 下载 </a-button> -->
       <a-button type="default" class="ml-8px" preIcon="mdi:plus" @click="handleOpenModal({})"> 新增 </a-button>
     </template>
     <template #action="{ record }">
-      <button @click="handleGoToPageQuery(record, `/manage/mapView`)" class="action-btn" title=""> 布点 </button>
+      <button @click="handleGoToPageQuery(record)" class="action-btn" title=""> 布点 </button>
       <button @click="handleOpenModal(record)" class="action-btn" title="修改">
         <SvgIcon name="edit" />
       </button>
@@ -32,11 +33,11 @@
 </template>
 
 <script setup lang="ts">
-  import { computed, onMounted } from 'vue';
-  import { useRouter } from 'vue-router';
+  import { computed, ref } from 'vue';
+  // import { useRouter } from 'vue-router';
   import { BasicTable } from '/@/components/Table';
   import { SvgIcon } from '/@/components/Icon';
-  import { Popconfirm } from 'ant-design-vue';
+  import { message, Popconfirm } from 'ant-design-vue';
   // 引入动态列/表单配置函数 + 类型
   import { getColumns, getSearchFormSchema } from './cad.data';
   import { getMineFileList, deleteMineFile } from './cad.api';
@@ -44,9 +45,9 @@
   // import { useIntervalFn } from '@vueuse/core';
   import { useModal } from '/@/components/Modal';
   import MapEditModal from './components/MapEditModal.vue';
+  // import { initMap2d } from './app';
+  import MapView from './components/MapView.vue';
 
-  // 路由实例
-  const router = useRouter();
   // 弹框注册
   const [registerModal, { openModal }] = useModal();
 
@@ -104,20 +105,21 @@
    * @param record 当前行数据
    */
   async function handleDeleteRecord(record: any) {
-    try {
-      await deleteMineFile({ id: record.id });
-      await mapTable.reload();
-    } catch (error) {
-      console.error('删除失败:', error);
-    }
+    await deleteMineFile({ id: record.id });
+    message.error('删除成功');
+    await mapTable.reload();
   }
 
-  function handleGoToPageQuery(record: any, path: string) {
-    const mineCode = record.mineCode;
-    router.push({
-      path,
-      state: { mineCode },
-    });
+  function handleGoToPageQuery(record: any) {
+    selected.value = record;
+    showCAD.value = true;
+    // router.push({
+    //   path,
+    //   query: {
+    //     mineCode: record.mineCode,
+    //     wjId: record.wjId,
+    //   },
+    // });
   }
 
   /**
@@ -126,8 +128,9 @@
   function handleCancel() {
     // 取消操作,无逻辑(仅关闭气泡)
   }
-  // ========== 初始化 ==========
-  onMounted(async () => {});
+
+  const showCAD = ref(false);
+  const selected = ref();
 </script>
 
 <style lang="less" scoped>

+ 0 - 0
src/views/system/cadFile/mapView/index.vue → src/views/system/cadFile/mapView/index.txt