浏览代码

增加员工信息列表

mork 1 周之前
父节点
当前提交
c9f5be86f1
共有 7 个文件被更改,包括 1372 次插入67 次删除
  1. 2 0
      public/static/config/config.js
  2. 950 0
      public/static/plugins/mapDraw.js
  3. 10 0
      src/api/common.js
  4. 13 1
      src/components/LeftMenu.vue
  5. 102 5
      src/components/Map.vue
  6. 137 0
      src/components/Table.vue
  7. 158 61
      src/views/IndexView.vue

+ 2 - 0
public/static/config/config.js

@@ -4,6 +4,8 @@ var webConfig = {
     AUTH_USER_TOKEN_KEY: "SKY_OAUTH_USER_TOKEN",
     LOGIN_FAIL_CODE: [206, 207, 208, 212], // loginFailCodes
 
+    columnArr: [{id:"1742",mid:"1793",name:"申勤员工"}],
+
     // oauth 服务ID
     serviceId: '0',
     SCRIPT_OAUTH_URL: 'http://121.43.55.7:10086',

+ 950 - 0
public/static/plugins/mapDraw.js

@@ -0,0 +1,950 @@
+// 闭包封装:内部所有变量和方法全部私有化!
+(function (window) {
+  /**
+   * MapDraw 独立封装类
+   * 引入后直接 new MapDraw(mapboxMap实例) 即可使用
+   */
+  class MapDraw {
+      /**
+     * 构造函数:new MapDraw() 时自动执行
+     * @param {mapboxgl.Map} map - 已经初始化好的 mapbox 实例
+     */
+
+    constructor(map, callbacks = {}) {
+      const that = this;
+      // 接收 map 实例
+      that.map = map;
+      // 编辑完成后 → 调用这个回调把数据抛出去
+      that.onEditComplete = callbacks.onEditComplete || null;
+
+      that.tempData = null;            // 当前绘制的图形数据
+      that.tempSource = null;         // 当前绘制的source
+      that.tempPoints = [];           // 存储绘制的点
+      that.drawType = '';             // 绘制类型
+      that.isDrawing = false;         // 是否正在绘制
+      that.hoveredPolygonId = null;   // 当前悬停的面ID
+      that.tempLineSource = null;     // 当前绘制的线的source
+      that.itemId = '';               // 当前绘制的图形ID
+      that.totalDistance = 0;         // 总距离
+      that.drawMarkers = [];          // 存储节点标签
+      that.moveMarkerTips = null;     //移动节点显示提示标签
+
+      // 用一个变量防止双击触发单击
+      that.lastClickTime = 0;
+      that.clickTimer = null;
+      that.clickCount = 0;
+
+      // 编辑相关状态
+      that.mouseDownPos = null;        // 鼠标按下时的位置
+      that.isDragWhole = false;        // 拖拽整个图形
+      that.lastLngLat = null;          // 最后一次点击的经纬度
+      that.isEditMode = false;         // 编辑模式
+      that.isEditFlag = false;         // 是否正在编辑
+      that.selectedFeature = null;     // 当前选中的图形
+      that.selectedFeatureId = '';     // 当前选中图形的ID
+      that.layersIds = [];             // 当前选中图形的图层ID
+      that.editMarkers = [];           // 存储编辑节点的标记
+      that.isDragging = false;         // 是否正在拖拽
+      that.draggingPointIndex = -1;    // 正在拖拽的节点索引
+      that.dragEventHandlers = null;   // 拖拽事件处理器
+      that.dragEventDrawHandlers = null;   // 拖拽事件处理器2
+      that.unit = 'kilometers';        // 单位 (kilometers/meters)
+      that.unitLabel = 'km';           // 单位标签 (km/m)
+      that.editLayerIds = [];             // 当前选中图形的图层ID
+      
+      // 缓存事件句柄,用于精准解绑(核心防重复触发)
+      that._mapClickHandle = null;
+      that._mapDblClickHandle = null;
+      that._mapMouseDownHandle = null;
+      that._mapMouseMoveHandle = null;
+      that._mapMouseUpHandle = null;
+
+      // 加载地图绘制图层
+      that.loadDrawLayer();
+      // 绑定地图事件
+      that.bindMapEvents();
+    }
+    // 编辑后回调返回的完整数据格式
+    getCompleteFeature(feature) {
+      const that = this;
+      // 复制一个全新的对象,和原 feature 无关
+      let feat = JSON.parse(JSON.stringify(feature));
+      delete feat.properties.drawType;
+      delete feat.properties.isCircle;
+      if (that.onEditComplete) {
+        that.onEditComplete({
+          type: "Feature",
+          geometry: feat.geometry,
+          properties: feat.properties || {}
+        });
+      }
+    }
+
+    // 绑定地图事件
+    bindMapEvents() {
+      const that = this;
+
+      // ========== 精准解绑所有旧鼠标事件,防止触发两次 ==========
+      if(that._mapClickHandle) that.map.off('click', that._mapClickHandle);
+      if(that._mapDblClickHandle) that.map.off('dblclick', that._mapDblClickHandle);
+      if(that._mapMouseDownHandle) that.map.off('mousedown', that._mapMouseDownHandle);
+      if(that._mapMouseMoveHandle) that.map.off('mousemove', that._mapMouseMoveHandle);
+      if(that._mapMouseUpHandle) that.map.off('mouseup', that._mapMouseUpHandle);
+
+      // 清空旧句柄
+      that._mapClickHandle = null;
+      that._mapDblClickHandle = null;
+      that._mapMouseDownHandle = null;
+      that._mapMouseMoveHandle = null;
+      that._mapMouseUpHandle = null;
+
+      // 初始化编辑鼠标事件
+      that.initMapEditEvents();
+
+      // 单击事件【缓存句柄】
+      that._mapClickHandle = (e) => {
+        that.handleFeatureClick(e);
+        if (that.isEditMode) {
+          const now = Date.now();
+          const DOUBLE_CLICK_THRESHOLD = 300;
+
+          clearTimeout(that.clickTimer);
+          if (now - that.lastClickTime > DOUBLE_CLICK_THRESHOLD) {
+            that.clickCount = 1;
+            that.lastClickTime = now;
+            that.clickTimer = setTimeout(() => {
+              if (that.clickCount === 1) {
+                that.handleMapClick(e);
+              }
+              that.clickCount = 0;
+            }, 10);
+          } else {
+            that.clickCount = 2;
+            that.lastClickTime = 0;
+          }
+        }
+      };
+      that.map.on('click', that._mapClickHandle);
+
+      // 双击事件【缓存句柄】
+      that._mapDblClickHandle = (e) => {
+        clearTimeout(that.clickTimer);
+        that.clickCount = 0;
+        that.lastClickTime = 0;
+        that.handleMapDblClick(e);
+      };
+      that.map.on('dblclick', that._mapDblClickHandle);
+
+      // ========== 键盘 DEL 删除选中节点 ==========
+      that.bindDeleteHotkey();
+    }
+
+    initMapEditEvents() {
+      const that = this;
+
+      // 鼠标按下【缓存句柄】
+      that._mapMouseDownHandle = (evt) => {
+        // console.log('[ _mapMouseDownHandle ] >', that.selectedFeature)
+        if (!that.selectedFeature) return;
+        if(that.selectedFeature.properties.drawType === 'distance' || that.selectedFeature.properties.drawType === 'area') return;
+        // console.log('[ _mapMouseDownHandle ] >', evt)
+        that.mouseDownPos = evt.point;
+        that.lastLngLat = evt.lngLat;
+        that.isDragging = false;
+        evt.preventDefault();
+        that.map.getCanvas().style.cursor = 'grabbing';
+      };
+      that.map.on('mousedown', that._mapMouseDownHandle);
+
+      // 鼠标移动【缓存句柄】
+      that._mapMouseMoveHandle = (evt) => {
+        if (!that.selectedFeature) return;
+        if ((that.isEditMode || that.isEditFlag) && that.isDragging) {
+            that.map.getCanvas().style.cursor = 'move';
+            that.handleDrag(evt);
+        }
+       
+        // console.log('[ _mapMouseMoveHandle ] >', that.selectedFeature)
+        if (!that.mouseDownPos || !that.selectedFeature) return;
+        if(that.selectedFeature.properties.drawType === 'distance' || that.selectedFeature.properties.drawType === 'area') return;
+        that.draggingPointIndex = -1;
+        const dx = Math.abs(evt.point.x - that.mouseDownPos.x);
+        const dy = Math.abs(evt.point.y - that.mouseDownPos.y);
+        if (dx > 1 || dy > 1) {
+          that.isDragging = true;
+          const curLngLat = evt.lngLat;
+          const dLng = curLngLat.lng - that.lastLngLat.lng;
+          const dLat = curLngLat.lat - that.lastLngLat.lat;
+          that.clearEditMarkers();
+          that.moveWholeFeature(dLng, dLat);
+          that.lastLngLat = curLngLat;
+        }
+      };
+      that.map.on('mousemove', that._mapMouseMoveHandle);
+
+      // 鼠标抬起【缓存句柄】
+      that._mapMouseUpHandle = () => {
+        if (!that.selectedFeature) return;
+        
+        that.mouseDownPos = null;
+        if (that.isDragging) {
+          that.getCompleteFeature(that.selectedFeature);
+          if(that.selectedFeature.properties.drawType === 'distance' || that.selectedFeature.properties.drawType === 'area'){
+            that.clearEditMarkers();
+          }else{
+            that.showEditMarkers();
+          }
+        }else{
+          that.clearEditMarkers();
+        }
+        // console.log('[ _mapMouseUpHandle ] >', that.selectedFeature)
+        that.isDragging = false;
+        // that.draggingPointIndex = -1;
+        that.tempLineSource.setData({ type: 'FeatureCollection', features: [] });
+        that.map.getCanvas().style.cursor = '';
+        //  console.log('[ _mapMouseUpHandle==== ] >', that.selectedFeature)
+      };
+      that.map.on('mouseup', that._mapMouseUpHandle);
+    }
+
+    // 剩余原有方法完全不变
+    loadDrawLayer(){
+        const that = this;
+        if(!that.map.getSource('temp-line')){
+          that.map.addSource('temp-line', {
+            type: 'geojson',
+            data: { type: 'FeatureCollection', features: [] }
+          });
+          that.map.addLayer({
+            id: 'temp-line-layer',
+            type: 'line',
+            source: 'temp-line',
+            paint: {
+              'line-color': 'red',
+              'line-width': 2,
+              'line-dasharray': [3, 3]
+            }
+          });
+        }
+        that.tempLineSource = that.map.getSource('temp-line');
+        that.map.on('mousemove', (e) => {
+          if (!that.isDrawing) return
+          if(that.moveMarkerTips){
+            that.moveMarkerTips.setLngLat(e.lngLat);
+          }else{
+            let text = "鼠标双击完成";
+            if(that.drawType === 'circle' || that.drawType === 'rectangle'){
+              text = "鼠标双击/单击完成";
+            }
+            that.addMoveMarkerTips(e.lngLat, text);
+          }
+          const end = [e.lngLat.lng, e.lngLat.lat];
+          if (that.drawType === 'rectangle'){
+            if (that.tempPoints.length < 1) return;
+            const bbox = [
+              Math.min(that.tempPoints[0][0], end[0]),
+              Math.min(that.tempPoints[0][1], end[1]),
+              Math.max(that.tempPoints[0][0], end[0]),
+              Math.max(that.tempPoints[0][1], end[1])
+            ];
+            that.addToMap(turf.bboxPolygon(bbox))
+          }else if (that.drawType === 'circle' && that.tempPoints.length >= 1){
+            let center = that.tempPoints[0];
+            let radius = turf.distance(turf.point(center), turf.point(end), { units: 'kilometers' })
+            that.addToMap(turf.circle(center, radius, 64))
+          }
+          if (that.tempPoints.length < 1 || that.drawType === 'rectangle') return;
+          const mousePt = [e.lngLat.lng, e.lngLat.lat];
+          const lastPt = that.tempPoints[that.tempPoints.length - 1];
+          const line = turf.lineString([lastPt, mousePt]);
+          that.tempLineSource.setData(line);
+        });
+    }
+
+    startDraw(type, flag, unit) {
+      const that = this;
+      that.drawType = type
+      that.isDrawing = true
+      that.tempPoints = []
+      that.tempLineSource.setData({ type: 'FeatureCollection', features: [] })
+      that.itemId = 'draw-' + Date.now();
+      that.map.getCanvas().style.cursor = 'crosshair';
+      that.totalDistance = 0;
+      that.unit = unit || 'kilometers';
+      that.unitLabel = that.unit === 'kilometers' ? 'km' : 'm';
+      flag = flag || true;
+      that.isEditDrawTool(flag);
+    }
+
+    isEditDrawTool(flag) {
+      const that = this;
+      that.isEditMode = flag;
+      if (!that.isEditMode) {
+        that.clearEditMarkers();
+        that.selectedFeature = null;
+        that.selectedFeatureId = '';
+        that.layersIds = [];
+      }
+      // console.log('[ isEditDrawTool ] >', that.selectedFeature)
+    }
+
+    isEdit(flag) {
+      const that = this;
+      that.isEditFlag = flag;
+      if (!that.isEditFlag) {
+        that.clearEditMarkers();
+        that.selectedFeature = null;
+        that.selectedFeatureId = '';
+        that.layersIds = [];
+      }
+      // console.log('[ isEdit ] >', that.selectedFeature)
+    }
+    
+    handleMapClick(e) {
+      const that = this;
+      if (!that.isDrawing) return
+      const coord = [e.lngLat.lng, e.lngLat.lat]
+      that.tempPoints.push(coord)
+      if (that.drawType === 'point') {
+        let feature = turf.point(coord)
+        feature.properties.drawType = 'point'
+        feature.properties.isCircle = false;
+        that.addToMap(feature)
+        that.finishDraw()
+      }
+      if (that.drawType === 'line' && that.tempPoints.length >= 2) {
+        let feature = turf.lineString(that.tempPoints)
+        feature.properties.drawType = 'line'
+        feature.properties.isCircle = false;
+        that.addToMap(feature)
+      }
+      if (that.drawType === 'polygon' && that.tempPoints.length >= 2) {
+        if(that.tempPoints.length >= 3){
+          let feature = turf.polygon([[...that.tempPoints, that.tempPoints[0]]])
+          feature.properties.drawType = 'polygon'
+          feature.properties.isCircle = false;
+          that.addToMap(feature)
+        }else{
+          let feature = turf.lineString(that.tempPoints)
+          feature.properties.drawType = 'polygon'
+          feature.properties.isCircle = false;
+          that.addToMap(feature)
+        }
+      }
+      if (that.drawType === 'circle' && that.tempPoints.length >= 2) {
+        const center = that.tempPoints[0]
+        const radius = turf.distance(turf.point(center), turf.point(that.tempPoints[1]), { units: that.unit })
+        let feature = turf.circle(center, radius, 64)
+        feature.properties.drawType = 'circle'
+        feature.properties.isCircle = true;
+        that.addToMap(feature)
+        that.finishDraw()
+      }
+      if (that.drawType === 'distance' && that.tempPoints.length >= 2) {
+        let feature = turf.lineString(that.tempPoints)
+        feature.properties.drawType = 'distance'
+        feature.properties.isCircle = false;
+        that.addToMap(feature)
+        const distance = turf.distance(turf.point(that.tempPoints[0]), turf.point(that.tempPoints[1]), { units: that.unit })
+        that.totalDistance += distance;
+        that.addMarker(e.lngLat, that.totalDistance.toFixed(2) + " " + that.unitLabel);  
+      }
+      if (that.drawType === 'area' && that.tempPoints.length >= 2) {
+        if(that.tempPoints.length >= 3){
+          let feature = turf.polygon([[...that.tempPoints, that.tempPoints[0]]])
+          feature.properties.drawType = 'area'
+          feature.properties.isCircle = false;
+          that.addToMap(feature)
+          const area = turf.area(feature)
+          that.totalDistance += area;
+        }else{
+          let feature = turf.lineString(that.tempPoints)
+          feature.properties.drawType = 'area'
+          feature.properties.isCircle = false;
+          that.addToMap(feature)
+        }
+      }
+      if (that.drawType === 'rectangle' && that.tempPoints.length >= 2) {
+        that.finishDraw()
+      }
+      that.updateTempLayer()
+    }
+
+    handleMapDblClick(e) {
+      const that = this;
+      if (!that.isDrawing || that.drawType === 'point') return
+      if (that.drawType === 'area' && that.tempPoints.length >= 2) {
+        if(that.tempPoints.length >= 3){
+          let feature = turf.polygon([[...that.tempPoints, that.tempPoints[0]]])
+          feature.properties.drawType = 'area'
+          feature.properties.isCircle = false;
+          that.addToMap(feature)
+          const areaNumber = (turf.area(feature)/1000000).toFixed(2);
+          that.addMarker(e.lngLat, areaNumber + ' 平方公里');  
+        }else{
+          let feature = turf.lineString(that.tempPoints)
+          feature.properties.drawType = 'area'
+          feature.properties.isCircle = false;
+          that.addToMap(feature)
+          const distance = turf.distance(turf.point(that.tempPoints[0]), turf.point(that.tempPoints[1]), { units: that.unit })
+          that.totalDistance += distance;
+          that.addMarker(e.lngLat, that.totalDistance.toFixed(2) + " " + that.unitLabel);  
+        }
+      }
+      that.finishDraw()
+    }
+
+    updateTempLayer() {
+      const that = this;
+      let feature
+      if (that.drawType === 'point' && that.tempPoints.length) feature = turf.point(that.tempPoints[0])
+      else if (that.drawType === 'line' && that.tempPoints.length >= 2) feature = turf.lineString(that.tempPoints)
+      else if (that.drawType === 'polygon' && that.tempPoints.length >= 2) feature = turf.lineString([...that.tempPoints, that.tempPoints[0]])
+      else if (that.drawType === 'circle' && that.tempPoints.length >= 1) feature = turf.point(that.tempPoints[0])
+      else if (that.drawType === 'distance' && that.tempPoints.length >= 2) feature = turf.lineString(that.tempPoints)
+      else if (that.drawType === 'area' && that.tempPoints.length >= 2) feature = turf.lineString([...that.tempPoints, that.tempPoints[0]])
+      
+      that.tempSource?.setData(feature || { type: 'FeatureCollection', features: [] })
+    }
+
+    addMoveMarkerTips(pt, text) {
+      const that = this;
+      let el = document.createElement('div');
+          el.className = 'marker-label-tips';
+          el.innerText = text;
+      that.moveMarkerTips = new mapboxgl.Marker(el, { anchor: 'center', offset: [0, -30] })
+            .setLngLat(pt)
+            .addTo(that.map);
+    }
+
+    addMarker(pt, text) {
+      const that = this;
+      let el = document.createElement('div');
+          el.className = 'marker-label-tips';
+          el.innerText = text;
+      let marker = new mapboxgl.Marker(el, { anchor: 'center' })
+            .setLngLat(pt)
+            .addTo(that.map);
+      that.drawMarkers.push(marker);
+    }
+
+    addEditMarker(coord, index) {
+      const that = this;
+      let el = document.createElement('div');
+      el.className = 'edit-marker';
+      el.style.width = '10px';
+      el.style.height = '10px';
+      el.style.borderRadius = '50%';
+      el.style.backgroundColor = 'red';
+      el.style.border = '2px solid white';
+      el.style.cursor = 'pointer';
+
+      el.addEventListener('mousedown', (e) => {
+        e.stopPropagation();
+        that.isDragging = true;
+        that.draggingPointIndex = index;
+        that.map.getCanvas().style.cursor = 'grabbing';
+      });
+      
+      let marker = new mapboxgl.Marker(el)
+        .setLngLat(coord)
+        .addTo(that.map);
+      that.editMarkers.push(marker);
+
+      if(!that.selectedFeature.properties.isCircle){
+        that.insertTwoMiddlePoints(marker, index);
+      }
+    }
+
+    clearNodeMarkers() {
+      const that = this;
+      that.drawMarkers.forEach(m => m.remove());
+      that.drawMarkers = [];
+    }
+
+    clearEditMarkers() {
+      const that = this;
+      that.editMarkers.forEach(marker => marker.remove());
+      that.editMarkers = [];
+    }
+
+    showEditMarkers() {
+      const that = this;
+      if (!that.selectedFeature) return;
+      const feature = that.selectedFeature;
+      if (feature.type === 'Feature') {
+        if (feature.geometry.type === 'Point') {
+          that.addEditMarker(feature.geometry.coordinates, 0);
+        } else if (feature.geometry.type === 'LineString') {
+          feature.geometry.coordinates.forEach((coord, index) => {
+            that.addEditMarker(coord, index);
+          });
+        } else if (feature.geometry.type === 'Polygon') {
+          feature.geometry.coordinates[0].forEach((coord, index) => {
+            if(index == feature.geometry.coordinates[0].length - 1){
+              return;
+            }
+            that.addEditMarker(coord, index);
+          });
+        }
+      }
+    }
+
+    clearAll() {
+      const that = this;
+      that.clearNodeMarkers();
+      that.clearEditMarkers();
+      that.selectedFeature = null;
+      that.selectedFeatureId = '';
+      that.layersIds = [];
+      const layers = that.map.getStyle().layers;
+      layers.sort((a, b) => a.type.localeCompare(b.type));
+      layers.forEach(layer => {
+        if (layer.id.startsWith('draw-')) {
+          if(layer.id.indexOf("-point") !== -1){
+            that.map.removeLayer(layer.id)
+          }
+          if(layer.id.indexOf("-line") !== -1){
+            that.map.removeLayer(layer.id)
+            let ids = layer.id.replace("-line",'');
+            that.map.removeSource(ids)
+          }
+          if(layer.id.indexOf("-polygon") !== -1){
+            that.map.removeLayer(layer.id)
+          }
+        }
+      })
+    }
+
+    addToMap(feature) {
+      const that = this;
+      let id = that.itemId;
+      if (!that.map.getSource(id)) {
+        that.map.addSource(id, { type: 'geojson', data: feature })
+        if(that.drawType === 'line'){
+          that.map.addLayer({ id: id + '-line', type: 'line', source: id, paint: { 'line-color': 'red', 'line-width': 2 } })
+        }else if(that.drawType === 'polygon'){
+          if(that.tempPoints.length >= 3){
+            that.map.addLayer({ id: id + '-polygon', type: 'fill', source: id, paint: { 'fill-color': 'red', 'fill-opacity': 0.3 }})
+          }
+          that.map.addLayer({ id: id + '-line', type: 'line', source: id, paint: { 'line-color': 'red', 'line-width': 2 } })
+        }else if(that.drawType === 'circle'){
+          that.map.addLayer({ id: id + '-polygon', type: 'fill', source: id, paint: { 'fill-color': 'red', 'fill-opacity': 0.3 }})
+          that.map.addLayer({ id: id + '-line', type: 'line', source: id, paint: { 'line-color': 'red', 'line-width': 2 } })
+        }else if(that.drawType === 'distance'){
+          that.map.addLayer({ id: id + '-line', type: 'line', source: id, paint: { 'line-color': 'red', 'line-width': 2 } })
+        }else if(that.drawType === 'area'){
+          if(that.tempPoints.length >= 3){
+            that.map.addLayer({ id: id + '-polygon', type: 'fill', source: id, paint: { 'fill-color': 'red', 'fill-opacity': 0.3 }})
+          }
+          that.map.addLayer({ id: id + '-line', type: 'line', source: id, paint: { 'line-color': 'red', 'line-width': 2 } })
+        }else if(that.drawType === 'rectangle'){
+          that.map.addLayer({ id: id + '-polygon', type: 'fill', source: id, paint: { 'fill-color': 'red', 'fill-opacity': 0.3 }})
+          that.map.addLayer({ id: id + '-line', type: 'line', source: id, paint: { 'line-color': 'red', 'line-width': 2 } })
+        }else{
+          that.map.addLayer({ id: id + '-point', type: 'circle', source: id, paint: { 'circle-radius': 5, 'circle-color': 'red' } })
+        }
+      }else{
+        that.map.getSource(id).setData(feature)
+        if(that.tempPoints.length >= 3 && (that.drawType === 'area' || that.drawType === 'polygon')){
+          if(!that.map.getLayer(id + '-polygon')){
+            that.map.addLayer({ id: id + '-polygon', type: 'fill', source: id, paint: { 'fill-color': 'red', 'fill-opacity': 0.3 }})
+          }
+        }
+      }
+      that.tempData = feature;
+    }
+
+    finishDraw() {
+      const that = this;
+      that.getCompleteFeature(that.tempData);
+      that.isDrawing = false
+      that.drawType = ''
+      that.tempPoints = []
+      that.tempSource?.setData({ type: 'FeatureCollection', features: [] })
+      that.tempLineSource.setData({ type: 'FeatureCollection', features: [] })
+      that.map.getCanvas().style.cursor = '';
+      if(that.moveMarkerTips){
+        that.moveMarkerTips.remove();
+        that.moveMarkerTips=null;
+      }
+    }
+
+    handleFeatureClick(e) {
+      const that = this;
+      const drawLayers = that.map.getStyle().layers
+        .filter(layer => layer.id.startsWith('draw-'))
+        .map(layer => layer.id);
+      const point = e.point;
+      const buffer = 5;
+      const box = [
+        [point.x - buffer, point.y - buffer],
+        [point.x + buffer, point.y + buffer]
+      ];
+      // 追加自定义绘制图层
+      that.editLayerIds.forEach(layerId => {
+        drawLayers.push(layerId);
+      })
+
+      const features = that.map.queryRenderedFeatures(box, {
+        layers: drawLayers
+      });
+      //  console.log('[ =====handleFeatureClick===== ] >', that.selectedFeature)
+      if (features.length > 0) {
+        if(that.isEditFlag){// 编辑绘制
+            const feature = features[0];
+            const sourceId = feature.layer.source;
+            if (!that.map.getSource(sourceId)) return;
+            that.selectedFeatureId = sourceId;
+
+            const sourceData = that.map.getSource(sourceId)._data;
+            if(sourceData.geometry){
+              that.selectedFeature = JSON.parse(JSON.stringify(sourceData));
+            }else{
+              sourceData.features.forEach(item => {
+                if(item.properties.dms_id === feature.properties.dms_id){
+                  that.selectedFeature = JSON.parse(JSON.stringify(item));
+                  return;
+                }
+              })
+            }
+            // 深拷贝切断引用
+            // that.selectedFeature = JSON.parse(JSON.stringify(feature));
+            that.getCompleteFeature(that.selectedFeature);
+            that.clearEditMarkers();
+            if(that.selectedFeature.properties.drawType === 'distance' || that.selectedFeature.properties.drawType === 'area') return;
+            that.showEditMarkers();
+        }else{ // 编辑工具绘制
+          const feature = features[0];
+          const layerId = feature.layer.id;
+          const featureId = layerId.split('-').slice(0, -1).join('-');
+          if (!that.map.getSource(featureId)) return;
+          that.selectedFeatureId = featureId;
+          const sourceData = that.map.getSource(featureId)._data;
+          that.selectedFeature = JSON.parse(JSON.stringify(sourceData));
+          // console.log('[ handleFeatureClick ] >', that.selectedFeature)
+          that.clearEditMarkers();
+          if(that.selectedFeature.properties.drawType === 'distance' || that.selectedFeature.properties.drawType === 'area') return;
+          that.showEditMarkers();
+        }
+        
+      } else {
+        that.clearEditMarkers();
+        that.selectedFeature = null;
+        that.selectedFeatureId = '';
+        // console.log('[ handleFeatureClick======== ] >', that.selectedFeature)
+      }
+    }
+    
+    // 编辑绘制点击事件  弃用  已被 handleFeatureClick 替代
+    handleEditDrawClick(e) {
+      const that = this;
+      const point = e.point;
+      const buffer = 5;
+      const box = [
+        [point.x - buffer, point.y - buffer],
+        [point.x + buffer, point.y + buffer]
+      ];
+      const features = that.map.queryRenderedFeatures(box, {
+        layers: that.editLayerIds
+      });
+      // console.log('[ handleEditDrawClick ] >', features)
+      if (features.length > 0) {
+        const feature = features[0];
+        const sourceId = feature.layer.source;
+        if (!that.map.getSource(sourceId)) return;
+        that.selectedFeatureId = sourceId;
+
+        const sourceData = that.map.getSource(sourceId)._data;
+        if(sourceData.geometry){
+          that.selectedFeature = JSON.parse(JSON.stringify(sourceData));
+        }else{
+          sourceData.features.forEach(item => {
+            if(item.properties.dms_id === feature.properties.dms_id){
+              that.selectedFeature = JSON.parse(JSON.stringify(item));
+              return;
+            }
+          })
+        }
+
+        // 深拷贝切断引用
+        // that.selectedFeature = JSON.parse(JSON.stringify(feature));
+        that.getCompleteFeature(that.selectedFeature);
+        that.clearEditMarkers();
+        that.showEditMarkers();
+      } else {
+        that.selectedFeature = null;
+        that.selectedFeatureId = '';
+      }
+    }
+
+    moveWholeFeature(dx, dy) {
+      const that = this;
+      if (!that.selectedFeature) return;
+      const feature = that.selectedFeature;
+      if (feature.geometry.type === 'Point') {
+        feature.geometry.coordinates[0] += dx;
+        feature.geometry.coordinates[1] += dy;
+      } else if (feature.geometry.type === 'LineString') {
+        feature.geometry.coordinates.forEach(coord => {
+          coord[0] += dx;
+          coord[1] += dy;
+        });
+      } else if (feature.geometry.type === 'Polygon') {
+        if(feature.properties.isCircle){
+          const centerPt = turf.centroid(feature);
+          const center = centerPt.geometry.coordinates;
+          const newCenter = [center[0] + dx, center[1] + dy];
+          const radiusMeters = turf.distance(center, feature.geometry.coordinates[0][0], { units: 'meters' });
+          const newCircle = turf.circle(newCenter, radiusMeters, {
+            units: 'meters',
+            steps: 64
+          });
+          newCircle.properties = feature.properties;
+          that.selectedFeature = newCircle;
+        } else {
+          feature.geometry.coordinates.forEach(ring => {
+            ring.forEach(coord => {
+              coord[0] += dx;
+              coord[1] += dy;
+            });
+          });
+        }
+      }
+      that.map.getSource(that.selectedFeatureId).setData(that.selectedFeature);
+      const sourceData = that.map.getSource(that.selectedFeatureId)._data;
+      that.selectedFeature = JSON.parse(JSON.stringify(sourceData));
+    }
+
+    editCircleVertex(newPoint) {
+      const that = this;
+      const feature = that.selectedFeature;
+      const centerPt = turf.centroid(feature);
+      const center = centerPt.geometry.coordinates;
+      const radiusMeters = turf.distance(center, newPoint, { units: 'meters' });
+      if (radiusMeters < 5) return;
+      const newCircle = turf.circle(center, radiusMeters, {
+        units: 'meters',
+        steps: 64
+      });
+      newCircle.properties = feature.properties;
+      const line = turf.lineString([center, newPoint]);
+      that.tempLineSource.setData(line);
+      that.selectedFeature = newCircle;
+      return newCircle;
+    }
+
+    insertTwoMiddlePoints(marker, index) {
+      const that = this;
+      marker.getElement().addEventListener('click', (e) => {
+        e.stopPropagation();
+        if (!that.selectedFeature) return;
+
+        const geom = that.selectedFeature.geometry;
+        let coords = [];
+        let isPolygon = false;
+
+        if (geom.type === 'LineString') {
+          coords = [...geom.coordinates];
+        } else if (geom.type === 'Polygon') {
+          coords = [...geom.coordinates[0]];
+          isPolygon = true;
+        }
+
+        if (coords.length < 2) return;
+
+        if (isPolygon) {
+          // ======================
+          // 面对称加两点(左边1个 + 右边1个)
+          // ======================
+          let pureCoords = coords.slice(0, -1);
+          const total = pureCoords.length;
+          let realIndex = index;
+          if (index === coords.length - 1) {
+            realIndex = 0;
+          }
+          const prevIdx = (realIndex - 1 + total) % total;
+          const nextIdx = (realIndex + 1) % total;
+          const prevPt = pureCoords[prevIdx];
+          const currPt = pureCoords[realIndex];
+          const nextPt = pureCoords[nextIdx];
+
+          const midPrev = [(prevPt[0] + currPt[0]) / 2, (prevPt[1] + currPt[1]) / 2];
+          const midNext = [(currPt[0] + nextPt[0]) / 2, (currPt[1] + nextPt[1]) / 2];
+
+          pureCoords.splice(realIndex, 0, midPrev);
+          pureCoords.splice(realIndex + 2, 0, midNext);
+
+          coords = [...pureCoords, pureCoords[0]];
+          geom.coordinates[0] = coords;
+        } else {
+          // ======================
+          // 线和面对称加两点(左边1个 + 右边1个)
+          // ======================
+          if (index === 0) {
+            // 起点 → 只在右侧加点(和面对齐)
+            const nextPt = coords[index + 1];
+            const midNext = [(coords[index][0] + nextPt[0]) / 2, (coords[index][1] + nextPt[1]) / 2];
+            coords.splice(index + 1, 0, midNext);
+          }
+          else if (index === coords.length - 1) {
+            // 终点 → 只在左侧加点
+            const prevPt = coords[index - 1];
+            const midPrev = [(prevPt[0] + coords[index][0]) / 2, (prevPt[1] + coords[index][1]) / 2];
+            coords.splice(index, 0, midPrev);
+          }
+          else {
+            // 中间点 → 左右各加 1 点(和面完全一样!)
+            const prevPt = coords[index - 1];
+            const nextPt = coords[index + 1];
+            const currPt = coords[index];
+
+            const midPrev = [(prevPt[0] + currPt[0]) / 2, (prevPt[1] + currPt[1]) / 2];
+            const midNext = [(currPt[0] + nextPt[0]) / 2, (currPt[1] + nextPt[1]) / 2];
+
+            coords.splice(index, 0, midPrev);
+            coords.splice(index + 2, 0, midNext);
+          }
+
+          geom.coordinates = coords;
+        }
+
+        that.refreshFeature();
+      });
+    }
+    // ========== 键盘 DEL 删除选中节点 / 图形 ==========
+    bindDeleteHotkey() {
+      const that = this;
+      // 先清掉旧事件,防止多实例、上下文错乱
+      window.removeEventListener('keydown', that._deleteKeyHandler);
+      // 保存成实例方法,保证永远指向最新实例
+      that._deleteKeyHandler = function (e) {
+        // 🔥 这里用 that,永远是当前最新实例
+        if (e.key === 'Delete' && that.selectedFeature  && (that.isEditMode || that.isEditFlag)) {
+          e.preventDefault();
+          // console.log('DEL 触发 - 当前图形:', that.selectedFeature);
+          // 如果正在编辑、有选中节点 → 删除当前节点
+          if (that.draggingPointIndex !== -1) {
+            that.deleteVertex(that.draggingPointIndex);
+          } 
+          // else {
+          //   that.deleteSelected();
+          // }
+        }
+      };
+      window.addEventListener('keydown', that._deleteKeyHandler);
+
+    }
+
+    // ==========  删除顶点(点/线/面 通用) ==========
+    deleteVertex(index) {
+      const that = this;
+      if (!that.selectedFeature) return;
+
+      const geom = that.selectedFeature.geometry;
+      let coords;
+      let isPolygon = false;
+
+      // 先重置拖拽状态!防止索引错乱
+      that.draggingPointIndex = -1;
+      that.isDragging = false;
+
+      if (geom.type === 'LineString') {
+        coords = geom.coordinates;
+        if (coords.length <= 2) return; // 线至少保留2个点
+      } 
+      else if (geom.type === 'Polygon') {
+        isPolygon = true;
+        coords = geom.coordinates[0];
+        if (coords.length <= 4) return; // 面至少保留3个点
+      } 
+
+      // 删除顶点
+      coords.splice(index, 1);
+      // 闭合面处理
+      if (isPolygon) {
+        if (index === 0) {
+          coords[coords.length - 1] = coords[0];
+        }
+      } 
+      // 刷新
+      that.refreshFeature();
+    }
+    refreshFeature() {
+      const that = this;
+      if (!that.selectedFeature || !that.selectedFeatureId) return;
+      // ========== 必须重置拖拽状态!否则必乱 ==========
+      that.draggingPointIndex = -1;
+      that.isDragging = false;
+      that.map.getSource(that.selectedFeatureId).setData(that.selectedFeature);
+      that.selectedFeature = JSON.parse(JSON.stringify(that.map.getSource(that.selectedFeatureId)._data));
+      that.clearEditMarkers();
+      that.showEditMarkers();
+    }
+    
+    handleDrag(e) {
+      const that = this;
+      // console.log("handleDrag",that.draggingPointIndex);
+      if (!that.selectedFeature || that.draggingPointIndex === -1) return;
+      if(that.selectedFeature.properties.drawType === 'distance' || that.selectedFeature.properties.drawType === 'area') return;
+      let feature = that.selectedFeature;
+      let newCoord = [e.lngLat.lng, e.lngLat.lat];
+      if(that.selectedFeature.properties.isCircle){
+          that.clearEditMarkers();
+          feature = that.editCircleVertex(newCoord);
+      }else{
+        if (feature.geometry.type === 'Point') {
+          feature.geometry.coordinates = newCoord;
+        } else if (feature.geometry.type === 'LineString') {
+          feature.geometry.coordinates[that.draggingPointIndex] = newCoord;
+        } else if (feature.geometry.type === 'Polygon') {
+          feature.geometry.coordinates[0][that.draggingPointIndex] = newCoord;
+          if (that.draggingPointIndex === 0) {
+            feature.geometry.coordinates[0][feature.geometry.coordinates[0].length - 1] = newCoord;
+          }
+        }
+        that.clearEditMarkers();
+        that.showEditMarkers();
+      }
+      that.selectedFeature = JSON.parse(JSON.stringify(feature));
+      that.map.getSource(that.selectedFeatureId).setData(feature);
+      that.getCompleteFeature(that.selectedFeature);
+      
+      // console.log("handleDrag selectedFeature",that.selectedFeature);
+    }
+
+    setEditLayerIds(arr){
+      const that = this;
+      that.editLayerIds = arr;
+    }
+    
+    deleteSelected() {
+      let that = this;
+      if (!that.selectedFeatureId) return;
+      const layers = window.mapboxMap.getStyle().layers;
+      layers.forEach(layer => {
+        if (layer.id.startsWith(that.selectedFeatureId)) {
+          that.map.removeLayer(layer.id);
+        }
+      });
+      that.map.removeSource(that.selectedFeatureId);
+      that.clearEditMarkers();
+      that.selectedFeature = null;
+      that.selectedFeatureId = '';
+      that.layersIds = [];
+    }
+
+  }
+
+  function init(map, options) {
+    const instance = new MapDraw(map, options);
+    return {
+      startDraw: (type, flag, unit) => instance.startDraw(type, flag, unit),
+      isEdit: (flag) => instance.isEdit(flag),
+      clearAll: () => instance.clearAll(),
+      setEditLayerIds: (arr) => instance.setEditLayerIds(arr),
+    };
+  }
+  window.MapDraw = { init };
+
+})(window);

+ 10 - 0
src/api/common.js

@@ -21,9 +21,19 @@ const updateContent = (params) => {
   return postform(webConfig.DMS_URL + '/content/updateContent', params)
 }
 
+//获得数据列表接口
+const getDmsDataList = (params) => {
+  return postform(webConfig.DMS_URL + "/content/selectContentList", params);
+};
+//根据模型id查询模型详情接口
+const getModelById = (params) => {
+  return postform(webConfig.DMS_URL + "/model/getModelById", params);
+};
 export default {
   login,
   updatePassword,
   getDmsTypes,
   updateContent,
+  getDmsDataList,
+  getModelById,
 }

+ 13 - 1
src/components/LeftMenu.vue

@@ -8,6 +8,7 @@
             :popper-append-to-body="false"
             :fetch-suggestions="querySearchAsync"
             placeholder="请输入项目名称或地址"
+            clearable :clear-icon="CloseBold"
             @select="handleSelect"
             >
             <!-- <template slot-scope="{ item }">
@@ -99,6 +100,7 @@ export default {
         }, 500);
     },
     selectItem(param){
+        let that = this;
         this.checkItem = param.checkItem;
         // let Lon = param['point_wgs84'].split(',')[0]
         // let Lat = param['point_wgs84'].split(',')[1]
@@ -119,7 +121,7 @@ export default {
           }
           const popupContent = `
           <div style="font-size:14px;line-height:1.6;padding:10px;">
-            <h4 style="margin:0 0 6px 0;color:#222;">详细信息</h4>
+            <h4 style="margin:0 0 6px 0;color:#222;"><span>内容信息</span><span class="more" id="popup-more-btn">员工信息>></span></h4>
             ${str}
           </div>
         `;
@@ -136,6 +138,16 @@ export default {
         .setHTML(popupContent) // 弹窗内容
         .addTo(window.mapboxMap);
 
+        setTimeout(() => {
+          const moreBtn = document.getElementById('popup-more-btn');
+          if (moreBtn) {
+            moreBtn.addEventListener('click', () => {
+              let pro = {properties:param}
+              that.$parent.handleMoreClick(pro);
+            });
+          }
+        }, 0);
+
     },
     handleChange(val) {
         // this.activeNames = val;

+ 102 - 5
src/components/Map.vue

@@ -5,6 +5,8 @@
 
   <VueJsonEditor v-if="editWinFlag" :editDataList="editDataList"></VueJsonEditor>
 
+  <Table :tableData="tableData" :columnModel="columnModel" :searchText="tableSearchText" v-if="tableShow" :isview="tableShow" ></Table>
+
    <!-- 十字准线元素 -->
   <div class="map-center-crosshair" v-if="btn_Aim_show"></div>
 
@@ -38,6 +40,7 @@ import qs from 'qs'
 import { ElMessage } from "element-plus";
 import LeftMenu from "@/components/LeftMenu.vue";
 import VueJsonEditor from '@/components/JsonEditor.vue';
+import Table from '@/components/Table.vue';
 import UTIL from '@/utils/util'
 import commonAPI from '@/api/common'
 export default {
@@ -45,13 +48,18 @@ export default {
   components: {
     VueJsonEditor,
     LeftMenu,
-  },
+    Table,
+    },
   data() {
     return {
       mouseCenter: "121.184665, 31.158609",
       center: [121.184665, 31.158609],
       dataList: "",
       areaDataList: [],
+      tableData:[],
+      columnModel:[],
+      tableShow:false,
+      tableSearchText:"",
       hoveredPolygonId: null,
       areaMarkers: [],
       btn_data_show: true,
@@ -162,6 +170,19 @@ export default {
     },
     initData() {
       this.creatMap();
+      this.getModelById();
+    },
+     //根据模型id查询模型详情
+    getModelById() {
+      let that = this;
+      let requestParams = {
+        modelId: webConfig.columnArr[0].mid, // 申勤员工ID
+      };
+      commonAPI.getModelById(requestParams).then((res) => {
+        if (res.code === 200) {
+          that.columnModel = res.content;
+        }
+      });
     },
     creatMap() {
       let that = this;
@@ -372,11 +393,12 @@ export default {
         const features = window.mapboxMap.queryRenderedFeatures(e.point, {
           layers: ['data-fill-layer'] // 只取这个图层
         });
+        that.tableShow = false;
         if (that.editFlag){
           if (features.length){
-            this.editWinFlag = true;
+            that.editWinFlag = true;
           }else{
-            // this.editWinFlag = false;
+            // that.editWinFlag = false;
           }
           return;
         };
@@ -403,7 +425,7 @@ export default {
 
         const popupContent = `
         <div style="font-size:14px;line-height:1.6;padding:10px;">
-          <h4 style="margin:0 0 6px 0;color:#222;">详细信息</h4>
+          <h4 style="margin:0 0 6px 0;color:#222;"><span>内容信息</span><span class="more" id="popup-more-btn">员工信息>></span></h4>
           ${str}
         </div>
         `;
@@ -417,8 +439,75 @@ export default {
         .setLngLat(e.lngLat)
         .setHTML(popupContent)
         .addTo(window.mapboxMap);
+
+        setTimeout(() => {
+          const moreBtn = document.getElementById('popup-more-btn');
+          if (moreBtn) {
+            moreBtn.addEventListener('click', () => {
+              that.handleMoreClick(fet);
+            });
+          }
+        }, 0);
       
     },
+    // 处理弹窗中"更多"按钮点击
+    handleMoreClick(fet) {
+      const that = this;
+      that.tableShow = false;
+      //1743 项目数据  1742 申勤员工
+      // 排序条件orderByType  1 升序 2 降序
+      let requestParams = {
+        columnId: webConfig.columnArr[0].id,
+        states: 0,
+        orderBy: JSON.stringify([{ field: "create_time", orderByType: 2 }]),
+        pageSize: 9999,
+        page: 0,
+      };
+      requestParams.search = JSON.stringify([
+        ...(requestParams.search ? JSON.parse(requestParams.search) : []),
+        {
+          field: "c_xmguid",  // 申勤员工 c_xmguid   项目数据 c_guid
+          searchType: 2,
+          content: { value: fet.properties.GUID },
+        },
+      ]);
+      commonAPI.getDmsDataList(requestParams).then((res) => {
+        if (res.code == 200){
+          let data = res.content.data;
+          data = data.map(item => {
+            // 给每个属性名称添加 c_ 前缀
+            const newItem = {};
+            for (const key in item) {
+              // 如果已经有c_
+              if (key.includes("c_")) {
+                let itemkey = key.replace(/c_/g, "");
+                newItem['c_' + itemkey] = item[key];
+              }else{ 
+                newItem[key] = item[key];
+              }
+            }
+            return newItem;
+          })
+          // console.log("data:", data);
+          that.tableData = data;
+          that.tableSearchText = "";
+          that.tableShow = true;
+        }else{
+          this.$message({ message: '无员工数据', type: 'info' })
+        }
+      });
+    },
+    setTableShow(data,text){
+      const that = this;
+      that.tableShow = false;
+      that.tableSearchText = text;
+      that.tableData = data;
+      // 使用 $nextTick 确保组件先销毁再重建
+      that.$nextTick(() => {
+        that.tableShow = true;
+      });
+      console.log("that.tableSearchText:", that.tableSearchText);
+    },
     // 复制指定元素内的文本
     copyDivText(selector) {
       const el = document.querySelector(selector);
@@ -621,7 +710,7 @@ export default {
     getVectorData() {
       let that = this;
        let param = {
-        "columnId": 1719,
+        "columnId": 1744,
         "token": localStorage.getItem("token")
       }
        axios.post(webConfig.DMS_URL + '/content/getVectorData', qs.stringify(param), 
@@ -685,6 +774,14 @@ export default {
 .custom-popup {
   z-index: 9;
 }
+.more{
+  float:right;
+  cursor: pointer;
+  transition: color 0.2s;
+}
+.more:hover {
+  color: #00A8FF;
+}
 </style>
 
 <style lang="less" scoped>

+ 137 - 0
src/components/Table.vue

@@ -0,0 +1,137 @@
+<template>
+  <el-dialog v-model="dialogTableVisible" title="员工信息" width="1200" draggable>
+    <div style="padding: 10px;">
+        <el-input v-model="searchText2" style="color: #000 !important;" size="small" placeholder="请输入姓名搜索" clearable :clear-icon="CloseBold" />
+    </div>
+    <el-table :data="paginatedTableData" style="height: 500px; overflow: auto;" >
+        <el-table-column
+          v-for="columnModel in modelFieldList"
+          :key="columnModel.id"
+          :fixed="columnModel.name == 'c_xm' ? true : false"
+          :property="columnModel.name"
+          :label="columnModel.alias"
+          :width="150"
+          show-overflow-tooltip
+        />
+    </el-table>
+
+    <!-- 分页控件 -->
+    <div class="pagination-section">
+        <span class="total-text">共{{ total }}条</span>
+        <el-pagination
+        layout="prev, pager, next"
+        :total="total"
+        :current-page="currentPage"
+        :page-size="pageSize"
+        @current-change="handleCurrentChange"
+        >
+        </el-pagination>
+    </div>
+  </el-dialog>
+
+</template>
+
+<script>
+export default {
+
+    data() {
+        return {
+            dialogTableVisible: false,
+            modelFieldList:[],
+            currentPage: 1,
+            pageSize: 10,
+            searchText2:""
+        }
+    },
+    props: {
+        tableData: {
+            type: Array,
+            default: []
+        },
+        columnModel: {
+            type: Array,
+            default: []
+        },
+        isview: {
+            type: Boolean,
+            default: false
+        },
+        searchText:{
+            type: String,
+            default: ''
+        }
+    },
+    created() {
+        let that = this;
+        that.searchText2 = that.searchText;
+        that.dialogTableVisible = that.isview;
+        console.log("that.searchText:", that.searchText);
+        let modelFields = JSON.parse(this.columnModel.fieldList);
+        // 无序
+        let keys = Object.keys(modelFields);
+        for (let i = 0; i < keys.length; i++) {
+            let obj = modelFields[keys[i]];
+            if (!obj.name) {
+                obj = JSON.parse(obj);
+            }
+            if (obj.name.includes("c_")) {
+                let itemkey = obj.name.replace(/c_/g, "");
+                obj.name = 'c_' + itemkey;
+            }
+            that.modelFieldList.push(obj);
+        }
+        this.modelFieldList.sort((a, b) => {
+            return a.index > b.index ? 1 : -1;
+        });
+    },
+    mounted() {
+    },
+    computed: {
+        filteredTableData() {
+            if (!this.searchText2) {
+                return this.tableData;
+            }
+            return this.tableData.filter((data) => {
+                const nameField = data.c_xm || data.name;
+                return nameField && nameField.toString().includes(this.searchText2);
+            });
+        },
+        total() {
+            return this.filteredTableData.length;
+        },
+        paginatedTableData() {
+            const start = (this.currentPage - 1) * this.pageSize;
+            const end = start + this.pageSize;
+            return this.filteredTableData.slice(start, end);
+        }
+    },
+    methods: {
+        handleSizeChange(val) {
+            this.pageSize = val;
+            this.currentPage = 1;
+        },
+        handleCurrentChange(val) {
+            this.currentPage = val;
+        }
+    }
+}
+</script>
+<style >
+/* 分页控件 */
+.pagination-section {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin: 0px 15px 0px 10px;
+}
+
+.total-text {
+  font-size: 14px;
+}
+</style>
+<style lang="less" scoped>
+/deep/.el-input__inner{
+    color: #000;
+}
+
+</style>

+ 158 - 61
src/views/IndexView.vue

@@ -7,14 +7,22 @@
     <div class="search-box">
       <div class="search-input">
         <el-autocomplete
-        v-model="searchText" 
-        popper-class="custom-dropdown"  
+        v-model="searchText"
+        popper-class="custom-dropdown"
         :popper-append-to-body="false"
         :fetch-suggestions="querySearchAsync"
-        placeholder="请输入地址"
+        :placeholder="selectType == '0' ? '请输入地址' : '请输入员工'"
+        clearable :clear-icon="CloseBold"
         @select="handleSelect"
         >
+          <template #append>
+          <el-select v-model="selectType" placeholder="请选择搜索类型" style="width: 80px">
+            <el-option label="地址" value="0" />
+            <el-option label="员工" value="1" />
+          </el-select>
+        </template>
         </el-autocomplete>
+
       </div>
   </div>
 
@@ -39,6 +47,7 @@
 </template>
 <script>
 import mapCommonApi from "@/api/mapCommon";
+import commonAPI from "@/api/common";
 import Map from "@/components/Map.vue";
 import Header from "@/components/Header.vue";
 import DrawMap from "@/components/DrawMap.vue";
@@ -55,26 +64,72 @@ export default {
       baseMap:'zwb',
       searchText: '',
       timeout:  null,
+      selectType:'0',
+      dataList:[]
     };
   },
   mounted() {
-    
+    this.initData();
   },
   beforeDestroy() {
     // 在组件销毁前移除事件监听器
   },
   methods: {
+    initData(){
+      this.getDmsDataList();
+    },
+    getDmsDataList(){
+      const that = this;
+      let requestParams = {
+        columnId: webConfig.columnArr[0].id,
+        states: 0,
+        orderBy: JSON.stringify([{ field: "create_time", orderByType: 2 }]),
+        pageSize: 99999,
+        page: 0,
+      };
+      // requestParams.search = JSON.stringify([
+      //   ...(requestParams.search ? JSON.parse(requestParams.search) : []),
+      //   {
+      //     field: "c_xm",  // 申勤员工 c_xmguid   项目数据 c_guid
+      //     searchType: 2,
+      //     content: { value: that.searchText },
+      //   },
+      // ]);
+      commonAPI.getDmsDataList(requestParams).then((res) => {
+        if (res.code == 200){
+          let data = res.content.data;
+          data = data.map(item => {
+            // 给每个属性名称添加 c_ 前缀
+            const newItem = {};
+            for (const key in item) {
+              // 如果已经有c_
+              if (key.includes("c_")) {
+                let itemkey = key.replace(/c_/g, "");
+                newItem['c_' + itemkey] = item[key];
+              }else{ 
+                newItem[key] = item[key];
+              }
+            }
+            return newItem;
+          })
+          // console.log("data:", data);
+          that.dataList = data;
+        }else{
+          this.$message({ message: '无员工数据', type: 'info' })
+        }
+      });
+    },
     selectMap(map){
       this.baseMap = map;
       if(map == 'zwb'){
         //切换底图后重新绑定
-        window.mapboxMap.on('style.load', this.$refs.childRef.initBaseMap("zwb")); 
+        window.mapboxMap.on('style.load', this.$refs.childRef.initBaseMap("zwb"));
       }else if(map == 'asb'){
         //切换底图后重新绑定
-        window.mapboxMap.on('style.load', this.$refs.childRef.initBaseMap("asb"));  
+        window.mapboxMap.on('style.load', this.$refs.childRef.initBaseMap("asb"));
       }else if(map == 'yxt'){
         //切换底图后重新绑定
-        window.mapboxMap.on('style.load', this.$refs.childRef.initBaseMap("yxt")); 
+        window.mapboxMap.on('style.load', this.$refs.childRef.initBaseMap("yxt"));
       }
     },
     querySearchAsync(queryString, cb) {
@@ -89,13 +144,28 @@ export default {
                 cb([]);
             }, 0);
         }else{
-          that.querySearchAddr(queryString,cb);
+          if(that.selectType == "0"){
+            that.querySearchAddr(queryString,cb);
+          }else{
+            that.queryTableData(queryString,cb);
+          }
+        }
+    },
+    queryTableData(text,cb){
+      const that = this;
+      let results = [];
+      that.dataList.filter(item => {
+        if(item.c_xm.includes(text)){
+          item.value = item.c_xm;
+          results.push(item);
         }
+      })
+      cb(results);
     },
-    querySearchAddr(address,cb){
+    querySearchAddr(text,cb){
       let that = this;
       mapCommonApi.getSerachAddress3({
-        "address": address
+        "address": text
       }).then((res) => {
          let results = res.content.data;
          results.forEach(item => {
@@ -114,64 +184,91 @@ export default {
     },
     handleSelect(item) {
         let that = this;
-        if(item){
-            let Lon = item.location.split(',')[0]
-            let Lat = item.location.split(',')[1]
-            let center = [parseFloat(Lon), parseFloat(Lat)]
-            window.mapboxMap.flyTo({
-                center: center,
-                zoom: 18,
-                pitch: 0,
-            });
+        if(that.selectType == "0"){
+          if(item){
+              let Lon = item.location.split(',')[0]
+              let Lat = item.location.split(',')[1]
+              let center = [parseFloat(Lon), parseFloat(Lat)]
+              window.mapboxMap.flyTo({
+                  center: center,
+                  zoom: 18,
+                  pitch: 0,
+              });
 
-          let jsondata = {
-              type: 'FeatureCollection',
-              features: [
-                {
-                  type: 'Feature',
-                  properties: {
-                    title: item.address,
-                    icon: 'location-icon'
-                  },
-                  geometry: {
-                    type: 'Point',
-                    coordinates: center
+            let jsondata = {
+                type: 'FeatureCollection',
+                features: [
+                  {
+                    type: 'Feature',
+                    properties: {
+                      title: item.address,
+                      icon: 'location-icon'
+                    },
+                    geometry: {
+                      type: 'Point',
+                      coordinates: center
+                    }
                   }
-                }
-              ]
-            };
+                ]
+              };
 
-          if(window.mapboxMap.getSource('point-source')){
-            window.mapboxMap.getSource('point-source').setData(jsondata);
-          }else{
-              window.mapboxMap.addSource('point-source', {
-                type: 'geojson',
-                data: jsondata
-              });
-              window.mapboxMap.addLayer({
-                id: 'location-layer',
-                type: 'symbol', // symbol = 图标/文字图层
-                source: 'point-source',
-                layout: {
-                  'icon-image': 'location-icon', // 使用自定义图标
-                  'icon-size': 1.5, // 图标大小
-                  'icon-allow-overlap': true, // 允许图标重叠
-                  'icon-rotate': 0, // 旋转角度
-                  'icon-offset': [0, -20] // 图标偏移(上下左右)
-                },
-                paint: {
-                  'icon-opacity': 1 // 透明度
-                }
-              });
+            if(window.mapboxMap.getSource('point-source')){
+              window.mapboxMap.getSource('point-source').setData(jsondata);
+            }else{
+                window.mapboxMap.addSource('point-source', {
+                  type: 'geojson',
+                  data: jsondata
+                });
+                window.mapboxMap.addLayer({
+                  id: 'location-layer',
+                  type: 'symbol', // symbol = 图标/文字图层
+                  source: 'point-source',
+                  layout: {
+                    'icon-image': 'location-icon', // 使用自定义图标
+                    'icon-size': 1.5, // 图标大小
+                    'icon-allow-overlap': true, // 允许图标重叠
+                    'icon-rotate': 0, // 旋转角度
+                    'icon-offset': [0, -20] // 图标偏移(上下左右)
+                  },
+                  paint: {
+                    'icon-opacity': 1 // 透明度
+                  }
+                });
+            }
           }
+        }else{
+          that.$refs.childRef.setTableShow(that.dataList,that.searchText)
         }
     },
-    
+
   }
 };
 
 </script>
 
+<style>
+.el-select__wrapper{
+  min-height: 40px !important;
+}
+.el-select__placeholder{
+  color: #fff !important;
+}
+.el-select__wrapper.is-focused{
+  min-height: 40px !important;
+}
+.el-popper.is-light{
+  background: #01346fe0 !important;
+  border: 1px solid #01346fe0 !important;
+}
+.el-select-dropdown__item{
+  color: #fff !important;
+}
+.el-select-dropdown__item.is-hovering{
+  background: linear-gradient(to right, #01346fe0, #02a7bd, #01346fe0) !important;
+  color: #fff !important;
+}
+</style>
+
 <style lang="less" scoped>
 
 .home {
@@ -202,7 +299,7 @@ export default {
     -webkit-backdrop-filter: blur(5px);
     backdrop-filter: blur(5px);
     background: #01346f99;
-    border-radius: 10px;
+    border-radius: 4px;
   }
 }
 .map-box{
@@ -216,8 +313,8 @@ export default {
       display: flex;
       gap: 5px;
       align-items: center;
-      background-color: #0440763d;
-      border: 1px solid #0440763d;
+      background-color: #01346f3d;
+      border: 1px solid #01346f3d;
       padding: 5px;
       border-radius: 5px;
       .map-item{
@@ -250,4 +347,4 @@ export default {
       }
     }
 }
-</style>
+</style>