套索工具(超叼版)
This commit is contained in:
@ -14,7 +14,7 @@ VITE_APP_MONITOR_ADMIN = '/admin/applications'
|
|||||||
VITE_APP_SNAILJOB_ADMIN = '/snail-job'
|
VITE_APP_SNAILJOB_ADMIN = '/snail-job'
|
||||||
|
|
||||||
# 生产环境
|
# 生产环境
|
||||||
VITE_APP_BASE_API = 'http://192.168.110.5:8899'
|
VITE_APP_BASE_API = 'http://192.168.110.2:8899'
|
||||||
|
|
||||||
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
||||||
VITE_BUILD_COMPRESS = gzip
|
VITE_BUILD_COMPRESS = gzip
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import { AxiosPromise } from 'axios';
|
import { AxiosPromise } from 'axios';
|
||||||
import { ProjectForm, ProjectQuery, ProjectVO } from '@/api/project/project/types';
|
import { childProjectQuery, ProjectForm, ProjectQuery, ProjectVO } from '@/api/project/project/types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询项目列表
|
* 查询项目列表
|
||||||
@ -150,3 +150,26 @@ export const delProject = (id: string | number | Array<string | number>) => {
|
|||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增子项目
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const addChildProject = (data: childProjectQuery) => {
|
||||||
|
return request({
|
||||||
|
url: '/project/project/sub',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询项目下的子项目列表
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const getChildProject = (id: string | number): AxiosPromise<childProjectQuery[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/project/project/list/sub/' + id,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
@ -128,6 +128,12 @@ export interface locationType {
|
|||||||
projectSite: string;
|
projectSite: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface childProjectQuery{
|
||||||
|
projectName:string;
|
||||||
|
pid:string;
|
||||||
|
id?:string
|
||||||
|
}
|
||||||
|
|
||||||
export interface ProjectForm extends BaseEntity {
|
export interface ProjectForm extends BaseEntity {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -77,8 +77,10 @@ import { Vector as VectorSource } from 'ol/source'; // OpenLayers的矢量数据
|
|||||||
import { Circle, Style, Stroke, Fill, Icon, Text } from 'ol/style'; // OpenLayers的样式类,用于定义图层的样式,包括圆形样式、基本样式、边框、填充和图标
|
import { Circle, Style, Stroke, Fill, Icon, Text } from 'ol/style'; // OpenLayers的样式类,用于定义图层的样式,包括圆形样式、基本样式、边框、填充和图标
|
||||||
import LineString from 'ol/geom/LineString'; // OpenLayers的线几何类,用于表示线状的地理数据
|
import LineString from 'ol/geom/LineString'; // OpenLayers的线几何类,用于表示线状的地理数据
|
||||||
import Polygon from 'ol/geom/Polygon'; // OpenLayers的多边形几何类,用于表示面状的地理数据
|
import Polygon from 'ol/geom/Polygon'; // OpenLayers的多边形几何类,用于表示面状的地理数据
|
||||||
|
import GeoJSON from 'ol/format/GeoJSON';
|
||||||
import * as turf from '@turf/turf';
|
import * as turf from '@turf/turf';
|
||||||
import { FeatureCollection } from 'geojson';
|
import { FeatureCollection, Geometry } from 'geojson';
|
||||||
|
import { MapViewFitter } from '@/utils/setMapCenter';
|
||||||
import { TreeInstance } from 'element-plus';
|
import { TreeInstance } from 'element-plus';
|
||||||
import { addProjectFacilities, addProjectPilePoint, addProjectSquare, listDXFProject, addInverter, addBoxTransformer } from '@/api/project/project';
|
import { addProjectFacilities, addProjectPilePoint, addProjectSquare, listDXFProject, addInverter, addBoxTransformer } from '@/api/project/project';
|
||||||
import { BatchUploader } from '@/utils/batchUpload';
|
import { BatchUploader } from '@/utils/batchUpload';
|
||||||
@ -123,15 +125,21 @@ const jsonData = computed(() => {
|
|||||||
});
|
});
|
||||||
return arr; // treeData.value;
|
return arr; // treeData.value;
|
||||||
});
|
});
|
||||||
console.log(jsonData);
|
const handlePosition = (data: any, node: any) => {
|
||||||
const handlePosition = (data: any, node) => {
|
const fitter = new MapViewFitter(map); // 传入你的 OpenLayers 地图实例
|
||||||
//切换中心点
|
const features = treeData.value[data.index]?.features; //features数组
|
||||||
const featureCollection: FeatureCollection = { type: 'FeatureCollection', features: treeData.value[data.index].features } as FeatureCollection;
|
console.log('🚀 ~ handlePosition ~ features:', features);
|
||||||
|
|
||||||
centerPosition.value = fromLonLat(turf.center(featureCollection).geometry.coordinates);
|
if (features?.length) {
|
||||||
|
const featureCollection: FeatureCollection<Geometry> = {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features
|
||||||
|
};
|
||||||
|
|
||||||
map.getView().setCenter(centerPosition.value);
|
fitter.fit(featureCollection);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCheckChange = (data: any, bool: boolean) => {
|
const handleCheckChange = (data: any, bool: boolean) => {
|
||||||
if (isMenuVisible.value) isMenuVisible.value = false;
|
if (isMenuVisible.value) isMenuVisible.value = false;
|
||||||
|
|
||||||
|
203
src/utils/lassoSelect.ts
Normal file
203
src/utils/lassoSelect.ts
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
import { Map as OLMap } from 'ol';
|
||||||
|
import VectorSource from 'ol/source/Vector';
|
||||||
|
import VectorLayer from 'ol/layer/Vector';
|
||||||
|
import { LineString, Polygon } from 'ol/geom';
|
||||||
|
import { Feature } from 'ol';
|
||||||
|
import { Style, Stroke, Fill } from 'ol/style';
|
||||||
|
import GeoJSON from 'ol/format/GeoJSON';
|
||||||
|
import { polygon as turfPolygon, booleanIntersects } from '@turf/turf';
|
||||||
|
import { toLonLat } from 'ol/proj';
|
||||||
|
import DragPan from 'ol/interaction/DragPan';
|
||||||
|
import MouseWheelZoom from 'ol/interaction/MouseWheelZoom';
|
||||||
|
|
||||||
|
export class LassoSelector {
|
||||||
|
private map: OLMap;
|
||||||
|
private drawLayer: VectorLayer<VectorSource>;
|
||||||
|
private drawSource: VectorSource;
|
||||||
|
private overlaySource: VectorSource;
|
||||||
|
private overlayLayer: VectorLayer<VectorSource>;
|
||||||
|
private drawing = false;
|
||||||
|
private coordinates: [number, number][] = [];
|
||||||
|
private targetSource: VectorSource;
|
||||||
|
private isShiftKeyDown = false;
|
||||||
|
private onSelectCallback: (selected: Feature[], isInvert?: boolean) => void;
|
||||||
|
private dragPanInteraction: DragPan | null = null;
|
||||||
|
private mouseWheelZoomInteraction: MouseWheelZoom | null = null;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
map: OLMap,
|
||||||
|
targetSource: VectorSource,
|
||||||
|
onSelect: (selected: Feature[], isInvert?: boolean) => void
|
||||||
|
) {
|
||||||
|
this.map = map;
|
||||||
|
this.targetSource = targetSource;
|
||||||
|
this.onSelectCallback = onSelect;
|
||||||
|
|
||||||
|
// 找出拖动和滚轮缩放交互
|
||||||
|
this.dragPanInteraction = this.map
|
||||||
|
.getInteractions()
|
||||||
|
.getArray()
|
||||||
|
.find((interaction) => interaction instanceof DragPan) as DragPan;
|
||||||
|
|
||||||
|
this.mouseWheelZoomInteraction = this.map
|
||||||
|
.getInteractions()
|
||||||
|
.getArray()
|
||||||
|
.find((interaction) => interaction instanceof MouseWheelZoom) as MouseWheelZoom;
|
||||||
|
|
||||||
|
this.drawSource = new VectorSource();
|
||||||
|
this.drawLayer = new VectorLayer({
|
||||||
|
source: this.drawSource,
|
||||||
|
style: new Style({
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: '#ff0000',
|
||||||
|
width: 2,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
this.map.addLayer(this.drawLayer);
|
||||||
|
|
||||||
|
this.overlaySource = new VectorSource();
|
||||||
|
this.overlayLayer = new VectorLayer({
|
||||||
|
source: this.overlaySource,
|
||||||
|
style: new Style({
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: 'rgba(255, 0, 0, 0.8)',
|
||||||
|
width: 2,
|
||||||
|
}),
|
||||||
|
fill: new Fill({
|
||||||
|
color: 'rgba(255, 0, 0, 0.3)',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
this.map.addLayer(this.overlayLayer);
|
||||||
|
|
||||||
|
this.bindEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bindEvents() {
|
||||||
|
// 禁用默认右键菜单
|
||||||
|
this.map.getViewport().addEventListener('contextmenu', (e) => e.preventDefault());
|
||||||
|
|
||||||
|
// pointerdown 捕获左键按下
|
||||||
|
this.map.getViewport().addEventListener('pointerdown', (e) => {
|
||||||
|
if (e.button === 0 && !this.drawing) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
this.isShiftKeyDown = e.shiftKey;
|
||||||
|
this.drawing = true;
|
||||||
|
this.coordinates = [];
|
||||||
|
this.drawSource.clear();
|
||||||
|
this.overlaySource.clear();
|
||||||
|
|
||||||
|
// 禁用拖动和缩放
|
||||||
|
if (this.dragPanInteraction) this.dragPanInteraction.setActive(false);
|
||||||
|
if (this.mouseWheelZoomInteraction) this.mouseWheelZoomInteraction.setActive(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// pointermove 画线
|
||||||
|
this.map.on('pointermove', (evt) => {
|
||||||
|
if (!this.drawing) return;
|
||||||
|
const coord = evt.coordinate as [number, number];
|
||||||
|
this.coordinates.push(coord);
|
||||||
|
this.renderLine();
|
||||||
|
this.renderPolygon();
|
||||||
|
});
|
||||||
|
|
||||||
|
// pointerup 捕获左键抬起
|
||||||
|
this.map.getViewport().addEventListener('pointerup', (e) => {
|
||||||
|
if (e.button === 0 && this.drawing) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
this.drawing = false;
|
||||||
|
this.handleDrawEnd();
|
||||||
|
|
||||||
|
// 恢复拖动和缩放
|
||||||
|
if (this.dragPanInteraction) this.dragPanInteraction.setActive(true);
|
||||||
|
if (this.mouseWheelZoomInteraction) this.mouseWheelZoomInteraction.setActive(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 防止拖动导致意外事件
|
||||||
|
this.map.getViewport().addEventListener('pointercancel', (e) => {
|
||||||
|
if (this.drawing) {
|
||||||
|
this.drawing = false;
|
||||||
|
this.drawSource.clear();
|
||||||
|
this.overlaySource.clear();
|
||||||
|
|
||||||
|
if (this.dragPanInteraction) this.dragPanInteraction.setActive(true);
|
||||||
|
if (this.mouseWheelZoomInteraction) this.mouseWheelZoomInteraction.setActive(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderLine() {
|
||||||
|
this.drawSource.clear();
|
||||||
|
if (this.coordinates.length >= 2) {
|
||||||
|
const line = new LineString(this.coordinates);
|
||||||
|
const feature = new Feature({ geometry: line });
|
||||||
|
this.drawSource.addFeature(feature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderPolygon() {
|
||||||
|
this.overlaySource.clear();
|
||||||
|
if (this.coordinates.length < 3) return;
|
||||||
|
|
||||||
|
const polygonCoords = [...this.coordinates, this.coordinates[0]];
|
||||||
|
const polygon = new Polygon([polygonCoords]);
|
||||||
|
const feature = new Feature({ geometry: polygon });
|
||||||
|
this.overlaySource.addFeature(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleDrawEnd() {
|
||||||
|
if (this.coordinates.length < 3) {
|
||||||
|
this.drawSource.clear();
|
||||||
|
this.overlaySource.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const first = this.coordinates[0];
|
||||||
|
const last = this.coordinates[this.coordinates.length - 1];
|
||||||
|
if (first[0] !== last[0] || first[1] !== last[1]) {
|
||||||
|
this.coordinates.push([...first]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const coords4326 = this.coordinates.map((c) => toLonLat(c));
|
||||||
|
const turfPoly = turfPolygon([coords4326]);
|
||||||
|
|
||||||
|
const geojson = new GeoJSON();
|
||||||
|
const selected: Feature[] = [];
|
||||||
|
|
||||||
|
this.targetSource.getFeatures().forEach((feature) => {
|
||||||
|
const geom = feature.getGeometry();
|
||||||
|
if (!geom) return;
|
||||||
|
|
||||||
|
const geomObj = geojson.writeGeometryObject(geom, {
|
||||||
|
featureProjection: 'EPSG:3857',
|
||||||
|
dataProjection: 'EPSG:4326',
|
||||||
|
}) as any;
|
||||||
|
|
||||||
|
if (
|
||||||
|
(geomObj.type === 'Polygon' || geomObj.type === 'MultiPolygon') &&
|
||||||
|
booleanIntersects(turfPoly, geomObj)
|
||||||
|
) {
|
||||||
|
selected.push(feature);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (selected.length) {
|
||||||
|
this.onSelectCallback(selected, this.isShiftKeyDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.drawSource.clear();
|
||||||
|
this.overlaySource.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.map.removeLayer(this.drawLayer);
|
||||||
|
this.map.removeLayer(this.overlayLayer);
|
||||||
|
}
|
||||||
|
}
|
58
src/utils/setMapCenter.ts
Normal file
58
src/utils/setMapCenter.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// MapViewFitter.ts
|
||||||
|
import { Map as OlMap } from 'ol';
|
||||||
|
import GeoJSON from 'ol/format/GeoJSON';
|
||||||
|
import { FeatureCollection } from 'geojson';
|
||||||
|
import { bbox as turfBbox, bboxPolygon as turfBboxPolygon } from '@turf/turf';
|
||||||
|
import type { Geometry } from 'ol/geom';
|
||||||
|
|
||||||
|
export class MapViewFitter {
|
||||||
|
private map: OlMap;
|
||||||
|
private format: GeoJSON;
|
||||||
|
|
||||||
|
constructor(map: OlMap) {
|
||||||
|
this.map = map;
|
||||||
|
this.format = new GeoJSON();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使地图视图自动适应传入的 GeoJSON FeatureCollection 范围
|
||||||
|
* @param featureCollection GeoJSON FeatureCollection
|
||||||
|
* @param padding 四周留白,默认为 [10, 10, 10, 10]
|
||||||
|
* @param duration 动画持续时间,默认为 1000 毫秒
|
||||||
|
*/
|
||||||
|
fit(featureCollection: FeatureCollection, padding: number[] = [10, 10, 10, 10], duration: number = 1000) {
|
||||||
|
if (!featureCollection?.features?.length) return;
|
||||||
|
|
||||||
|
const bbox = turfBbox(featureCollection); // [minX, minY, maxX, maxY]
|
||||||
|
const bboxPolygon = turfBboxPolygon(bbox); // Feature<Polygon>
|
||||||
|
|
||||||
|
const geometry: Geometry = this.format.readGeometry(bboxPolygon.geometry, {
|
||||||
|
dataProjection: 'EPSG:4326',
|
||||||
|
featureProjection: 'EPSG:3857'
|
||||||
|
});
|
||||||
|
|
||||||
|
const extent = geometry.getExtent();
|
||||||
|
|
||||||
|
this.map.getView().fit(extent, {
|
||||||
|
padding,
|
||||||
|
duration
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//示例
|
||||||
|
// import { MapViewFitter } from '@/utils/setMapCenter'; // 确保路径正确
|
||||||
|
|
||||||
|
// const fitter = new MapViewFitter(map); // 传入你的 OpenLayers 地图实例
|
||||||
|
// const features = xxx;//features数组
|
||||||
|
|
||||||
|
// if (features?.length) {
|
||||||
|
// const featureCollection = {
|
||||||
|
// type: 'FeatureCollection',
|
||||||
|
// features
|
||||||
|
// };
|
||||||
|
|
||||||
|
// fitter.fit(featureCollection);
|
||||||
|
// }
|
||||||
|
|
@ -6,16 +6,16 @@
|
|||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
<el-form-item label="请选择方阵:" prop="pid" label-width="100">
|
<el-form-item label="请选择方阵:" prop="pid" label-width="100">
|
||||||
<!-- <el-input v-model="queryParams.pid" placeholder="请选择" clearable /> -->
|
<!-- <el-input v-model="queryParams.pid" placeholder="请选择" clearable /> -->
|
||||||
<!-- <el-cascader
|
<el-cascader
|
||||||
:options="matrixOptions"
|
:options="matrixOptions"
|
||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
:props="{ value: 'id', label: 'matrixName' }"
|
:props="{ value: 'id', label: 'matrixName' }"
|
||||||
clearable
|
clearable
|
||||||
/> -->
|
/>
|
||||||
<el-select v-model="matrixValue" placeholder="请选择" @change="handleChange" clearable>
|
<!-- <el-select v-model="matrixValue" placeholder="请选择" @change="handleChange" clearable>
|
||||||
<el-option v-for="item in matrixOptions" :key="item.id" :label="item.matrixName" :value="item.id" />
|
<el-option v-for="item in matrixOptions" :key="item.id" :label="item.matrixName" :value="item.id" />
|
||||||
</el-select>
|
</el-select> -->
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" icon="Download" @click="handleQuery">导出周报</el-button>
|
<el-button type="primary" icon="Download" @click="handleQuery">导出周报</el-button>
|
||||||
|
@ -1,7 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="header flex justify-end">
|
<div class="header flex justify-between">
|
||||||
|
<div class="tips flex items-center justify-between">
|
||||||
|
<div class="dot1">未提交</div>
|
||||||
|
<div class="dot2">已提交</div>
|
||||||
|
<div class="dot3">已选择,待提交</div>
|
||||||
|
<el-tooltip class="box-item" effect="dark" content="右键拖动生成套索区域选中/取消图形" placement="bottom">
|
||||||
|
<i class="iconfont icon-wenhao"></i>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
<el-form :model="queryParams" ref="form" label-width="80px" inline class="flex items-center">
|
<el-form :model="queryParams" ref="form" label-width="80px" inline class="flex items-center">
|
||||||
<el-form-item label="请选择项目:" prop="pid" label-width="100" style="margin-bottom: 0">
|
<el-form-item label="请选择项目:" prop="pid" label-width="100" style="margin-bottom: 0; color: #fff">
|
||||||
<el-select v-model="selectedProjectId" placeholder="请选择" @change="handleSelect" clearable>
|
<el-select v-model="selectedProjectId" placeholder="请选择" @change="handleSelect" clearable>
|
||||||
<el-option v-for="item in ProjectList" :key="item.id" :label="item.name" :value="item.id" />
|
<el-option v-for="item in ProjectList" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
@ -45,15 +53,20 @@ import { useUserStoreHook } from '@/store/modules/user';
|
|||||||
import { getProjectSquare, listProgressCategory, addDaily, workScheduleListPosition } from '@/api/progress/plan';
|
import { getProjectSquare, listProgressCategory, addDaily, workScheduleListPosition } from '@/api/progress/plan';
|
||||||
import { ProgressCategoryVO, progressPlanDetailForm } from '@/api/progress/plan/types';
|
import { ProgressCategoryVO, progressPlanDetailForm } from '@/api/progress/plan/types';
|
||||||
import { Circle, Fill, Stroke, Style, Text } from 'ol/style';
|
import { Circle, Fill, Stroke, Style, Text } from 'ol/style';
|
||||||
import { defaults as defaultInteractions } from 'ol/interaction';
|
import { defaults as defaultInteractions, DragPan } from 'ol/interaction';
|
||||||
import Feature from 'ol/Feature';
|
import Feature from 'ol/Feature';
|
||||||
import { Point, Polygon } from 'ol/geom';
|
import { Point, Polygon } from 'ol/geom';
|
||||||
import VectorSource from 'ol/source/Vector';
|
import VectorSource from 'ol/source/Vector';
|
||||||
import VectorLayer from 'ol/layer/Vector';
|
import VectorLayer from 'ol/layer/Vector';
|
||||||
import Node from 'element-plus/es/components/tree/src/model/node.mjs';
|
import Node from 'element-plus/es/components/tree/src/model/node.mjs';
|
||||||
import { ElCheckbox } from 'element-plus';
|
import { ElCheckbox } from 'element-plus';
|
||||||
|
import { LassoSelector } from '@/utils/lassoSelect';
|
||||||
|
import { FeatureCollection, Geometry } from 'geojson';
|
||||||
|
import { MapViewFitter } from '@/utils/setMapCenter';
|
||||||
|
import PointerInteraction from 'ol/interaction/Pointer';
|
||||||
|
import { Coordinate } from 'ol/coordinate';
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
const selector = ref<LassoSelector | null>(null);
|
||||||
// 获取用户 store
|
// 获取用户 store
|
||||||
const userStore = useUserStoreHook();
|
const userStore = useUserStoreHook();
|
||||||
// 从 store 中获取项目列表和当前选中的项目
|
// 从 store 中获取项目列表和当前选中的项目
|
||||||
@ -122,7 +135,14 @@ const handleCheckChange = (data: any, checked: boolean, indeterminate: boolean)
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!checked) return (submitForm.value.id = ''); // 只处理第三级节点的选中事件
|
// if (!checked) return (submitForm.value.id = ''); // 只处理第三级节点的选中事件
|
||||||
|
if (!checked) {
|
||||||
|
// ✅ 只在取消的是当前 id 时清空
|
||||||
|
if (submitForm.value.id === data.id) {
|
||||||
|
submitForm.value.id = '';
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const parent = node.parent;
|
const parent = node.parent;
|
||||||
if (!parent) return;
|
if (!parent) return;
|
||||||
@ -131,6 +151,7 @@ const handleCheckChange = (data: any, checked: boolean, indeterminate: boolean)
|
|||||||
// 设置当前点击项为选中
|
// 设置当前点击项为选中
|
||||||
treeRef.value.setChecked(data.id, true, false);
|
treeRef.value.setChecked(data.id, true, false);
|
||||||
submitForm.value.id = data.id; // 设置提交表单的id
|
submitForm.value.id = data.id; // 设置提交表单的id
|
||||||
|
console.log('submitForm', submitForm.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
//清除某一级节点所有选中状态
|
//清除某一级节点所有选中状态
|
||||||
@ -213,6 +234,7 @@ const submit = () => {
|
|||||||
console.log('sunbmitForm', submitForm.value);
|
console.log('sunbmitForm', submitForm.value);
|
||||||
const { finishedDetailIdList, id } = submitForm.value;
|
const { finishedDetailIdList, id } = submitForm.value;
|
||||||
if (!id || finishedDetailIdList.length === 0) return proxy?.$modal.msgWarning('请选择图层以及日期');
|
if (!id || finishedDetailIdList.length === 0) return proxy?.$modal.msgWarning('请选择图层以及日期');
|
||||||
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
addDaily(submitForm.value)
|
addDaily(submitForm.value)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -267,7 +289,7 @@ const renderContent = (context, { node, data }) => {
|
|||||||
style: 'margin-right: 8px;',
|
style: 'margin-right: 8px;',
|
||||||
disabled: data.disabled
|
disabled: data.disabled
|
||||||
}),
|
}),
|
||||||
h('span', node.label)
|
h('span', [node.label])
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
if (node.level === 2) {
|
if (node.level === 2) {
|
||||||
@ -278,13 +300,58 @@ const renderContent = (context, { node, data }) => {
|
|||||||
style: 'margin-right: 8px;',
|
style: 'margin-right: 8px;',
|
||||||
disabled: !data.threeChildren || data.threeChildren.length == 0
|
disabled: !data.threeChildren || data.threeChildren.length == 0
|
||||||
}),
|
}),
|
||||||
h('span', node.label)
|
h('span', { onDblclick: () => handlePosition(data, node) }, node.label)
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
return h('span', node.label);
|
return h('span', node.label);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handlePosition = (data: any, node: any) => {
|
||||||
|
if (!data.threeChildren) return;
|
||||||
|
|
||||||
|
const fitter = new MapViewFitter(map); // 传入你的 OpenLayers 地图实例
|
||||||
|
const features: GeoJSON.Feature[] = data.threeChildren.map((item) => {
|
||||||
|
if ('type' in item && item.type === 'Feature') {
|
||||||
|
return item as GeoJSON.Feature;
|
||||||
|
}
|
||||||
|
const raw = item;
|
||||||
|
|
||||||
|
let coordinates: any;
|
||||||
|
if (raw.type === 'Polygon') {
|
||||||
|
coordinates = [(raw.positions as [string, string][]).map(([lng, lat]) => [parseFloat(lng), parseFloat(lat)])];
|
||||||
|
} else if (raw.type === 'Point') {
|
||||||
|
const [lng, lat] = raw.positions as [string, string];
|
||||||
|
coordinates = [parseFloat(lng), parseFloat(lat)];
|
||||||
|
} else {
|
||||||
|
throw new Error(`Unsupported geometry type: ${raw.type}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'Feature',
|
||||||
|
geometry: {
|
||||||
|
type: raw.type,
|
||||||
|
coordinates
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
id: raw.id,
|
||||||
|
name: raw.name,
|
||||||
|
status: raw.status,
|
||||||
|
finishDate: raw.finishDate
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
if (features?.length) {
|
||||||
|
const featureCollection: FeatureCollection<Geometry> = {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features
|
||||||
|
};
|
||||||
|
|
||||||
|
fitter.fit(featureCollection);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//切换项目重置方阵
|
//切换项目重置方阵
|
||||||
const resetMatrix = () => {
|
const resetMatrix = () => {
|
||||||
matrixValue.value = undefined;
|
matrixValue.value = undefined;
|
||||||
@ -330,7 +397,13 @@ const initOLMap = () => {
|
|||||||
new TileLayer({
|
new TileLayer({
|
||||||
// 设置图层的数据源为XYZ类型。XYZ是一个通用的瓦片图层源,它允许你通过URL模板来获取瓦片
|
// 设置图层的数据源为XYZ类型。XYZ是一个通用的瓦片图层源,它允许你通过URL模板来获取瓦片
|
||||||
source: new XYZ({
|
source: new XYZ({
|
||||||
url: 'https://webrd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}'
|
url: 'https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}'
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
new TileLayer({
|
||||||
|
// 设置图层的数据源为XYZ类型。XYZ是一个通用的瓦片图层源,它允许你通过URL模板来获取瓦片
|
||||||
|
source: new XYZ({
|
||||||
|
url: 'http://webst02.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
@ -360,20 +433,7 @@ const initOLMap = () => {
|
|||||||
const zoom = map.getView().getZoom();
|
const zoom = map.getView().getZoom();
|
||||||
const scale = Math.max(zoom / 10, 1); // 缩放比例,根据需要调整公式
|
const scale = Math.max(zoom / 10, 1); // 缩放比例,根据需要调整公式
|
||||||
map.forEachFeatureAtPixel(e.pixel, (feature: Feature) => {
|
map.forEachFeatureAtPixel(e.pixel, (feature: Feature) => {
|
||||||
const geomType = feature.getGeometry().getType();
|
toggleFeatureHighlight(feature);
|
||||||
if (feature.get('status') === '2' || geomType != 'Polygon') return; // 如果是完成状态,直接返回
|
|
||||||
|
|
||||||
const isHighlighted = feature.get('highlighted') === true;
|
|
||||||
|
|
||||||
if (isHighlighted) {
|
|
||||||
feature.setStyle(defaultStyle(feature.get('name'), scale)); // 清除高亮样式
|
|
||||||
feature.set('highlighted', false);
|
|
||||||
submitForm.value.finishedDetailIdList = submitForm.value.finishedDetailIdList.filter((id) => id !== feature.get('id')); // 从已完成列表中移除
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
feature.setStyle(highlightStyle(feature.get('name'), scale));
|
|
||||||
feature.set('highlighted', true);
|
|
||||||
submitForm.value.finishedDetailIdList.push(feature.get('id')); // 添加到已完成列表
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
map.getView().on('change:resolution', () => {
|
map.getView().on('change:resolution', () => {
|
||||||
@ -389,6 +449,58 @@ const initOLMap = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 4. 添加 pointermove 鼠标悬停事件
|
||||||
|
let lastFeature: Feature | null = null;
|
||||||
|
|
||||||
|
map.on('pointermove', (evt) => {
|
||||||
|
map.getTargetElement().style.cursor = '';
|
||||||
|
|
||||||
|
const feature = map.forEachFeatureAtPixel(evt.pixel, (f) => f);
|
||||||
|
const zoom = map.getView().getZoom();
|
||||||
|
const scale = Math.max(zoom / 10, 1);
|
||||||
|
|
||||||
|
// 👉 若当前划入的 feature 是不允许 hover 的,直接跳过处理
|
||||||
|
const currStatus = feature?.get('status');
|
||||||
|
const currHighlighted = feature?.get('highlighted');
|
||||||
|
if (feature && (currStatus === '2' || currHighlighted === true || feature.getGeometry()?.getType() !== 'Polygon')) {
|
||||||
|
return; // ❌ 不执行 hover 效果,也不更新 lastFeature
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ 若进入了新的可 hover feature
|
||||||
|
if (feature && feature !== lastFeature) {
|
||||||
|
if (lastFeature) {
|
||||||
|
const lastStatus = lastFeature.get('status');
|
||||||
|
const lastHighlighted = lastFeature.get('highlighted');
|
||||||
|
|
||||||
|
if (lastStatus === '2') {
|
||||||
|
lastFeature.setStyle(successStyle(lastFeature.get('name'), scale));
|
||||||
|
} else if (lastHighlighted === true) {
|
||||||
|
lastFeature.setStyle(highlightStyle(lastFeature.get('name'), scale));
|
||||||
|
} else {
|
||||||
|
lastFeature.setStyle(defaultStyle(lastFeature.get('name'), scale));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
feature.setStyle(hoverStyle(feature.get('name'), scale));
|
||||||
|
map.getTargetElement().style.cursor = 'pointer';
|
||||||
|
lastFeature = feature;
|
||||||
|
} else if (!feature && lastFeature) {
|
||||||
|
// ✅ 鼠标移出所有图形时恢复
|
||||||
|
const lastStatus = lastFeature.get('status');
|
||||||
|
const lastHighlighted = lastFeature.get('highlighted');
|
||||||
|
|
||||||
|
if (lastStatus === '2') {
|
||||||
|
lastFeature.setStyle(successStyle(lastFeature.get('name'), scale));
|
||||||
|
} else if (lastHighlighted === true) {
|
||||||
|
lastFeature.setStyle(highlightStyle(lastFeature.get('name'), scale));
|
||||||
|
} else {
|
||||||
|
lastFeature.setStyle(defaultStyle(lastFeature.get('name'), scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
lastFeature = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const highlightStyle = (name, scale) => {
|
const highlightStyle = (name, scale) => {
|
||||||
@ -401,13 +513,13 @@ const highlightStyle = (name, scale) => {
|
|||||||
color: 'rgba(255,165,0,0.3)' // 半透明橙色
|
color: 'rgba(255,165,0,0.3)' // 半透明橙色
|
||||||
}),
|
}),
|
||||||
text: new Text({
|
text: new Text({
|
||||||
font: '14px Microsoft YaHei',
|
font: '10px Microsoft YaHei',
|
||||||
text: name,
|
text: name,
|
||||||
placement: 'line', // 👈 关键属性
|
placement: 'line', // 👈 关键属性
|
||||||
offsetX: 50, // 向右偏移 10 像素
|
offsetX: 50, // 向右偏移 10 像素
|
||||||
offsetY: 20, // 向下偏移 5 像素
|
offsetY: 20, // 向下偏移 5 像素
|
||||||
scale,
|
scale,
|
||||||
fill: new Fill({ color: 'orange' })
|
fill: new Fill({ color: '#FFFFFF' })
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -419,13 +531,13 @@ const defaultStyle = (name, scale) => {
|
|||||||
width: 2
|
width: 2
|
||||||
}),
|
}),
|
||||||
text: new Text({
|
text: new Text({
|
||||||
font: '12px Microsoft YaHei',
|
font: '10px Microsoft YaHei',
|
||||||
text: name,
|
text: name,
|
||||||
scale,
|
scale,
|
||||||
placement: 'line', // 👈 关键属性
|
placement: 'line', // 👈 关键属性
|
||||||
offsetX: 50, // 向右偏移 10 像素
|
offsetX: 50, // 向右偏移 10 像素
|
||||||
offsetY: 20, // 向下偏移 5 像素
|
offsetY: 20, // 向下偏移 5 像素
|
||||||
fill: new Fill({ color: '#003366 ' })
|
fill: new Fill({ color: '#FFFFFF ' })
|
||||||
}),
|
}),
|
||||||
fill: new Fill({ color: 'skyblue' })
|
fill: new Fill({ color: 'skyblue' })
|
||||||
});
|
});
|
||||||
@ -438,7 +550,7 @@ const successStyle = (name, scale) => {
|
|||||||
width: 2
|
width: 2
|
||||||
}),
|
}),
|
||||||
text: new Text({
|
text: new Text({
|
||||||
font: '14px Microsoft YaHei',
|
font: '10px Microsoft YaHei',
|
||||||
text: name,
|
text: name,
|
||||||
scale,
|
scale,
|
||||||
placement: 'line', // 👈 关键属性
|
placement: 'line', // 👈 关键属性
|
||||||
@ -450,6 +562,27 @@ const successStyle = (name, scale) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const hoverStyle = (name, scale) => {
|
||||||
|
return new Style({
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: 'orange',
|
||||||
|
width: 2
|
||||||
|
}),
|
||||||
|
fill: new Fill({
|
||||||
|
color: 'rgba(255,165,0,0.3)' // 半透明橙色
|
||||||
|
}),
|
||||||
|
text: new Text({
|
||||||
|
font: '10px Microsoft YaHei',
|
||||||
|
text: name,
|
||||||
|
scale,
|
||||||
|
placement: 'line', // 👈 关键属性
|
||||||
|
offsetX: 50, // 向右偏移 10 像素
|
||||||
|
offsetY: 20, // 向下偏移 5 像素
|
||||||
|
fill: new Fill({ color: '#FFFFFF ' })
|
||||||
|
})
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建图层
|
* 创建图层
|
||||||
* @param {*} pointObj 坐标数组
|
* @param {*} pointObj 坐标数组
|
||||||
@ -477,7 +610,7 @@ const creatPoint = (pointObj: Array<any>, type: string, id: string, name?: strin
|
|||||||
|
|
||||||
const feature = new Feature({ geometry });
|
const feature = new Feature({ geometry });
|
||||||
const zoom = map.getView().getZoom();
|
const zoom = map.getView().getZoom();
|
||||||
const scale = Math.max(zoom / 10, 1); // 缩放比例,根据需要调整公式
|
const scale = Math.max(zoom / 30, 1); // 缩放比例,根据需要调整公式
|
||||||
const pointStyle = new Style({
|
const pointStyle = new Style({
|
||||||
image: new Circle({
|
image: new Circle({
|
||||||
radius: 2,
|
radius: 2,
|
||||||
@ -519,15 +652,77 @@ const addPointToMap = (features: Array<any>) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//选中几何图形
|
||||||
|
const toggleFeatureHighlight = (feature: Feature, addIfNotExist = true) => {
|
||||||
|
const zoom = map.getView().getZoom();
|
||||||
|
const scale = Math.max(zoom / 10, 1);
|
||||||
|
if (feature.get('status') === '2') return;
|
||||||
|
if (feature.getGeometry()?.getType() !== 'Polygon') return;
|
||||||
|
|
||||||
|
const isHighlighted = feature.get('highlighted') === true;
|
||||||
|
|
||||||
|
if (isHighlighted) {
|
||||||
|
feature.setStyle(defaultStyle(feature.get('name'), scale));
|
||||||
|
feature.set('highlighted', false);
|
||||||
|
const id = feature.get('id');
|
||||||
|
const idx = submitForm.value.finishedDetailIdList.indexOf(id);
|
||||||
|
if (idx > -1) submitForm.value.finishedDetailIdList.splice(idx, 1);
|
||||||
|
} else if (addIfNotExist) {
|
||||||
|
feature.setStyle(highlightStyle(feature.get('name'), scale));
|
||||||
|
feature.set('highlighted', true);
|
||||||
|
const id = feature.get('id');
|
||||||
|
if (!submitForm.value.finishedDetailIdList.includes(id)) submitForm.value.finishedDetailIdList.push(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 地图初始化
|
// 地图初始化
|
||||||
initOLMap();
|
initOLMap();
|
||||||
map.addLayer(sharedLayer);
|
map.addLayer(sharedLayer);
|
||||||
const canvas = document.createElement('canvas');
|
selector.value = new LassoSelector(map, sharedSource, (features, isInvert = false) => {
|
||||||
const ctx = canvas.getContext('2d', { willReadFrequently: true });
|
features.forEach((feature) => {
|
||||||
|
if (isInvert) {
|
||||||
|
// Shift + 左键 -> 只执行取消选中
|
||||||
|
if (feature.get('highlighted') === true) {
|
||||||
|
toggleFeatureHighlight(feature, false); // 取消选中,addIfNotExist = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 普通左键 -> 只执行选中
|
||||||
|
if (feature.get('highlighted') !== true) {
|
||||||
|
toggleFeatureHighlight(feature, true); // 选中,addIfNotExist = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
enableMiddleMousePan(map);
|
||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function enableMiddleMousePan(map: Map) {
|
||||||
|
// 先移除默认的 DragPan(通常响应左键)
|
||||||
|
const interactions = map.getInteractions();
|
||||||
|
interactions.forEach((interaction) => {
|
||||||
|
if (interaction instanceof DragPan) {
|
||||||
|
map.removeInteraction(interaction);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加只响应中键的 DragPan
|
||||||
|
const middleButtonDragPan = new DragPan({
|
||||||
|
condition: (event) => {
|
||||||
|
// 只允许中键 (mouse button 1) 拖动
|
||||||
|
return event.originalEvent instanceof MouseEvent && event.originalEvent.button === 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
map.addInteraction(middleButtonDragPan);
|
||||||
|
|
||||||
|
// 禁用中键点击默认滚动行为(浏览器可能会出现滚动箭头)
|
||||||
|
map.getViewport().addEventListener('mousedown', (e) => {
|
||||||
|
if (e.button === 1) e.preventDefault();
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -566,4 +761,40 @@ onMounted(() => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
.tips {
|
||||||
|
margin: 0 15px;
|
||||||
|
position: relative;
|
||||||
|
font-size: 18px;
|
||||||
|
color: #fff;
|
||||||
|
> div {
|
||||||
|
margin: 0 25px;
|
||||||
|
position: relative;
|
||||||
|
font-size: 12px;
|
||||||
|
&::before {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
left: -15px;
|
||||||
|
top: 30%;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dot1 {
|
||||||
|
&::before {
|
||||||
|
background-color: #1d6fe9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dot2 {
|
||||||
|
&::before {
|
||||||
|
background-color: #67c23a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dot3 {
|
||||||
|
&::before {
|
||||||
|
background-color: #ff8d1a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -43,6 +43,36 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="projectList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="projectList" @selection-change="handleSelectionChange">
|
||||||
|
<el-table-column type="expand" width="50">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<div class="w187.25 ml-12.5">
|
||||||
|
<el-button class="mb" type="primary" size="small" @click="handleOpenSetChild(row.id)" icon="plus">添加子项目</el-button>
|
||||||
|
|
||||||
|
<el-table :data="row.children" border stripe>
|
||||||
|
<el-table-column label="序号" type="index" width="55" align="center" />
|
||||||
|
<el-table-column label="名称" align="center" prop="projectName" width="296" />
|
||||||
|
<el-table-column label="创建时间" align="center" prop="createTime" width="199" />
|
||||||
|
<el-table-column fixed="right" align="center" label="操作" class-name="small-padding fixed-width" width="199">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-space>
|
||||||
|
<el-button
|
||||||
|
link
|
||||||
|
type="success"
|
||||||
|
icon="Edit"
|
||||||
|
@click="handleOpenSetChild(row.id, scope.row.id, scope.row.projectName)"
|
||||||
|
v-hasPermi="['project:project:edit']"
|
||||||
|
>修改
|
||||||
|
</el-button>
|
||||||
|
<el-button link type="danger" icon="Delete" @click="handleChildDel(scope.row.id)" v-hasPermi="['project:project:remove']"
|
||||||
|
>删除
|
||||||
|
</el-button>
|
||||||
|
</el-space>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="序号" type="index" width="60" align="center" />
|
<el-table-column label="序号" type="index" width="60" align="center" />
|
||||||
<el-table-column label="项目名称" align="center" prop="projectName">
|
<el-table-column label="项目名称" align="center" prop="projectName">
|
||||||
@ -278,21 +308,33 @@
|
|||||||
@close="polygonStatus = false"
|
@close="polygonStatus = false"
|
||||||
></open-layers-map>
|
></open-layers-map>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<el-dialog title="添加子项目" v-model="childProjectStatus" width="400">
|
||||||
|
<span>填写子项目名称</span>
|
||||||
|
<el-input v-model="childProjectForm.projectName"></el-input>
|
||||||
|
<template #footer>
|
||||||
|
<span>
|
||||||
|
<el-button @click="childProjectStatus = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSetChild">确定</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Project" lang="ts">
|
<script setup name="Project" lang="ts">
|
||||||
import {
|
import {
|
||||||
|
addChildProject,
|
||||||
addProject,
|
addProject,
|
||||||
addProjectFacilities,
|
addProjectFacilities,
|
||||||
addProjectPilePoint,
|
addProjectPilePoint,
|
||||||
addProjectSquare,
|
addProjectSquare,
|
||||||
delProject,
|
delProject,
|
||||||
|
getChildProject,
|
||||||
getProject,
|
getProject,
|
||||||
listProject,
|
listProject,
|
||||||
updateProject
|
updateProject
|
||||||
} from '@/api/project/project';
|
} from '@/api/project/project';
|
||||||
import { ProjectForm, ProjectQuery, ProjectVO, locationType } from '@/api/project/project/types';
|
import { ProjectForm, ProjectQuery, ProjectVO, childProjectQuery, locationType } from '@/api/project/project/types';
|
||||||
import amap from '@/components/amap/index.vue';
|
import amap from '@/components/amap/index.vue';
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { sys_normal_disable, project_category_type, project_type } = toRefs<any>(
|
const { sys_normal_disable, project_category_type, project_type } = toRefs<any>(
|
||||||
@ -306,6 +348,7 @@ const ids = ref<Array<string | number>>([]);
|
|||||||
const single = ref(true);
|
const single = ref(true);
|
||||||
const multiple = ref(true);
|
const multiple = ref(true);
|
||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
|
const childProjectStatus = ref(false);
|
||||||
const amapStatus = ref(false);
|
const amapStatus = ref(false);
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const projectFormRef = ref<ElFormInstance>();
|
const projectFormRef = ref<ElFormInstance>();
|
||||||
@ -313,6 +356,11 @@ const polygonStatus = ref(false);
|
|||||||
const dxfFile = ref(null);
|
const dxfFile = ref(null);
|
||||||
const projectId = ref<string>('');
|
const projectId = ref<string>('');
|
||||||
const designId = ref<string>('');
|
const designId = ref<string>('');
|
||||||
|
const childProjectForm = reactive<childProjectQuery>({
|
||||||
|
projectName: '',
|
||||||
|
pid: '',
|
||||||
|
id: ''
|
||||||
|
});
|
||||||
//被选中的节点
|
//被选中的节点
|
||||||
const nodes = ref<any>([]);
|
const nodes = ref<any>([]);
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
@ -563,6 +611,50 @@ const handleDelete = async (row?: ProjectVO) => {
|
|||||||
await getList();
|
await getList();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//删除子项目
|
||||||
|
const handleChildDel = async (id) => {
|
||||||
|
await proxy?.$modal.confirm('是否确认删除项目编号为"' + id + '"的数据项?').finally(() => (loading.value = false));
|
||||||
|
await delProject(id);
|
||||||
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
|
await getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
//增加/修改子项目
|
||||||
|
const handleOpenSetChild = async (pid, id?, name?) => {
|
||||||
|
childProjectStatus.value = true;
|
||||||
|
childProjectForm.id = id;
|
||||||
|
childProjectForm.pid = pid;
|
||||||
|
childProjectForm.projectName = name;
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetChildQuert = () => {
|
||||||
|
childProjectForm.id = '';
|
||||||
|
childProjectForm.pid = '';
|
||||||
|
childProjectForm.projectName = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
//增加/修改子项目
|
||||||
|
const handleSetChild = async () => {
|
||||||
|
if (!childProjectForm.projectName.trim()) return proxy.$modal.msgError('请填写项目名称');
|
||||||
|
if (childProjectForm.id) {
|
||||||
|
let res = await updateProject({ id: childProjectForm.id, projectName: childProjectForm.projectName });
|
||||||
|
if (res.code == 200) {
|
||||||
|
proxy.$modal.msgSuccess('修改成功');
|
||||||
|
childProjectStatus.value = false;
|
||||||
|
resetChildQuert();
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let res = await addChildProject(childProjectForm);
|
||||||
|
if (res.code == 200) {
|
||||||
|
proxy.$modal.msgSuccess('添加成功');
|
||||||
|
childProjectStatus.value = false;
|
||||||
|
resetChildQuert();
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
const handleExport = () => {
|
const handleExport = () => {
|
||||||
proxy?.download(
|
proxy?.download(
|
||||||
|
Reference in New Issue
Block a user