添加地图点击基地,数据填报bug修改

This commit is contained in:
扈兆增 2026-05-11 17:45:09 +08:00
parent 2eb818b61d
commit 7ab91f158e
12 changed files with 51718 additions and 51262 deletions

View File

@ -22,7 +22,9 @@
<a-button v-else type="primary" size="small" class="mr-2" @click="saveBtn"> <a-button v-else type="primary" size="small" class="mr-2" @click="saveBtn">
保存信息 保存信息
</a-button> </a-button>
<a-button type="primary" size="small"> 修改记录 </a-button> <a-button type="primary" size="small" @click="recordBtn">
修改记录
</a-button>
</div> </div>
</div> </div>
<div class="col-left" v-if="item.visible"> <div class="col-left" v-if="item.visible">
@ -69,6 +71,15 @@
</div> </div>
</a-col> </a-col>
</a-row> </a-row>
<a-modal
v-model:open="visible"
title="修改记录"
:footer="null"
width="900px"
:zIndex="2000"
>
123
</a-modal>
</div> </div>
</a-spin> </a-spin>
</template> </template>
@ -87,7 +98,7 @@ const props = defineProps({
default: "", default: "",
}, },
}); });
const value1 = ref(dayjs("2009-04-01")); const visible = ref(false);
const loading = ref(false); const loading = ref(false);
const tabledata = ref([]); const tabledata = ref([]);
console.log(BasicColumns); console.log(BasicColumns);
@ -114,6 +125,9 @@ const saveBtn = () => {
isEdit.value = false; isEdit.value = false;
console.log(tabledata.value); console.log(tabledata.value);
}; };
const recordBtn = () => {
visible.value = true;
};
onMounted(() => { onMounted(() => {
loading.value = true; loading.value = true;
const data = { const data = {

View File

@ -28,8 +28,8 @@
<a-button type="primary" :disabled="isEngConfig"> <a-button type="primary" :disabled="isEngConfig">
<i class="icon iconfont icon-topic mr-[5px]"></i> <i class="icon iconfont icon-topic mr-[5px]"></i>
电站专题 电站专题
</a-button </a-button></a-tooltip
></a-tooltip> >
</template> </template>
</a-tabs> </a-tabs>
</a-modal> </a-modal>
@ -68,12 +68,11 @@ const props = defineProps<{
// 'update:activeKey' v-model:active-key // 'update:activeKey' v-model:active-key
const emit = defineEmits<{ const emit = defineEmits<{
(e: "update:visible", value: boolean): void; (e: "update:visible", value: boolean): void;
(e: "update:activeKey", key: string): void;
(e: "change", key: string): void; (e: "change", key: string): void;
}>(); }>();
// activeKey // activeKey
const currentActiveKey = ref<string>(props.activeKey || ""); const currentActiveKey = ref<string>("");
// activeKey // activeKey
watch( watch(
@ -89,6 +88,8 @@ watch(
() => modelStore.params, () => modelStore.params,
(newVal) => { (newVal) => {
tabsConfig.value = handleTabs(newVal); tabsConfig.value = handleTabs(newVal);
let value = tabsConfig.value.find((item: any) => item.default);
currentActiveKey.value = value?.key;
}, },
{ deep: true, immediate: true } { deep: true, immediate: true }
); );
@ -96,7 +97,6 @@ watch(
const onTabChange = (key: string) => { const onTabChange = (key: string) => {
currentActiveKey.value = key; currentActiveKey.value = key;
// activeKey ( v-model) // activeKey ( v-model)
emit("update:activeKey", key);
// () // ()
emit("change", key); emit("change", key);
}; };

View File

@ -17,7 +17,8 @@ const ENGTabs: Array<any> = [
name: '基础信息', name: '基础信息',
key: 'basicInfo', key: 'basicInfo',
type: 'basic', type: 'basic',
url: '/bbi/siteBipc/getSiteBasicInfo' url: '/bbi/siteBipc/getSiteBasicInfo',
default: true // 默认显示
}, },
{ {
name: '阶段属性', name: '阶段属性',

File diff suppressed because it is too large Load Diff

View File

@ -67,7 +67,9 @@ export class MapOl implements MapInterface {
private pointLayerRegistry: Map<string, VectorLayer> = new Map(); private pointLayerRegistry: Map<string, VectorLayer> = new Map();
geoJsonData: any = null; geoJsonData: any = null;
geoJsonData1: any = null; geoJsonData1: any = null;
// ✅ 新增:声明用于存储 mask 事件监听器的引用,以便后续移除
private _maskPrerender: any = null;
private _maskPostrender: any = null;
// private BASEID: string = '01'; // private BASEID: string = '01';
constructor() { constructor() {
this.loadGeoJsonData(); this.loadGeoJsonData();
@ -75,18 +77,31 @@ export class MapOl implements MapInterface {
} }
private async loadGeoJsonData(): Promise<void> { private async loadGeoJsonData(): Promise<void> {
try { try {
const response = await fetch('/data/geoJson.json') const response = await fetch('/data/geoJson.json');
this.geoJsonData = await response.json() this.geoJsonData = await response.json();
} catch (error) { } catch (error) {
console.error('配置加载失败:', error) console.error('配置加载失败:', error);
}
} }
}
private async loadGeoJsonData1(): Promise<void> { private async loadGeoJsonData1(): Promise<void> {
try { try {
const response = await fetch('/data/geoJson1.json') const response = await fetch('/data/geoJson1.json');
this.geoJsonData1 = await response.json() let res = await response.json();
let json1 = {
crs: res.crs,
features: [],
totalFeatures: res.totalFeatures,
type: res.type
};
for (let i = 0; i < res.features.length; i++) {
if (res.features[i].properties.BASEID === '12') {
json1.features.push(res.features[i]);
}
}
console.log(json1);
this.geoJsonData1 = json1;
} catch (error) { } catch (error) {
console.error('配置加载失败:', error) console.error('配置加载失败:', error);
} }
} }
//地图初始化 //地图初始化
@ -238,14 +253,7 @@ export class MapOl implements MapInterface {
const features: Feature[] = []; const features: Feature[] = [];
dataArray.forEach((item: any) => { dataArray.forEach((item: any) => {
const { const { lgtd, lttd, stnm, iconCode, titleName, ennm } = item;
lgtd,
lttd,
stnm,
iconCode,
titleName,
ennm
} = item;
if (lgtd == null || lttd == null) { if (lgtd == null || lttd == null) {
return; return;
@ -317,7 +325,7 @@ export class MapOl implements MapInterface {
// 如果 currentResolution 变小 (放大地图)ratio 变大 -> icon 变大 // 如果 currentResolution 变小 (放大地图)ratio 变大 -> icon 变大
// 限制最大和最小缩放,防止过大或过小 // 限制最大和最小缩放,防止过大或过小
// let dynamicScale = baseScale * (baseResolution / (currentResolution || 1)); // let dynamicScale = baseScale * (baseResolution / (currentResolution || 1));
const currentZoom:any = this.view ? this.view.getZoom() : 4.5; const currentZoom: any = this.view ? this.view.getZoom() : 4.5;
let dynamicScale = 0.7 + (currentZoom - 4.5) * 0.08; let dynamicScale = 0.7 + (currentZoom - 4.5) * 0.08;
// 限制范围:最小 0.5,最大 3.0 (可根据需求调整) // 限制范围:最小 0.5,最大 3.0 (可根据需求调整)
@ -464,23 +472,25 @@ export class MapOl implements MapInterface {
}) })
}), }),
// ✅ 3. 调整 zIndex确保在底图之上可见 // ✅ 3. 调整 zIndex确保在底图之上可见
zIndex: 100, zIndex: 101,
visible: true visible: true
}); });
// 监听数据加载完成事件 // 监听数据加载完成事件
// vectorSource.on('featuresloadend', () => { vectorSource.on('featuresloadend', () => {
// // 获取所有加载的要素 // 获取所有加载的要素
// const features = vectorSource.getFeatures(); const features = vectorSource.getFeatures();
// const feature = features[0]; const feature = features[0];
// const geometry = feature.getGeometry(); const geometry = feature.getGeometry();
// console.log(geometry) console.log(geometry);
// // this.addClipToRasterLayer(this.layerRegistry.get(this.REGISTRY_KEY), geometry); // this.addClipToRasterLayer(this.layerRegistry.get(this.REGISTRY_KEY), geometry);
// // this.applyMapMask(geometry); // this.applyMapMask(geometry);
// }); });
// 4. 注册与添加 // 4. 注册与添加
this.layerRegistry.set(layer.key, vectorLayer); this.layerRegistry.set(layer.key, vectorLayer);
this.map.addLayer(vectorLayer); // this.map.addLayer(vectorLayer);
layer._layer = vectorLayer; layer._layer = vectorLayer;
const targetBaseLayer = this.layerRegistry.get(this.REGISTRY_KEY);
this.applyMapMask(targetBaseLayer as TileLayer, this.geoJsonData1);
console.log(`矢量图层 [${layer.key}] 已加载: ${layer.url}`); console.log(`矢量图层 [${layer.key}] 已加载: ${layer.url}`);
} }
@ -570,6 +580,24 @@ export class MapOl implements MapInterface {
// } // }
// }); // });
// } // }
// 在 addBaseDataLayer 方法的 vector 分支末尾,或者专门提供一个方法来激活遮罩
enableNortheastMask(): void {
// 1. 获取全量底图图层
const baseLayer = this.layerRegistry.get(this.REGISTRY_KEY);
// 2. 检查是否已加载东北边界数据
if (!this.geoJsonData1) {
console.warn('东北边界数据尚未加载');
return;
}
if (baseLayer && baseLayer instanceof TileLayer) {
console.log('正在应用东北区域遮罩...');
this.applyMapMask(baseLayer, this.geoJsonData1);
} else {
console.warn('未找到全量底图图层或图层类型错误');
}
}
/** /**
* *
* @param regionId ID ( "hebei", "13", "01" Key ) * @param regionId ID ( "hebei", "13", "01" Key )
@ -1188,7 +1216,156 @@ export class MapOl implements MapInterface {
container.appendChild(closeBtn); container.appendChild(closeBtn);
this.map.addOverlay(overlay); this.map.addOverlay(overlay);
} }
/**
*
* @param rasterLayer (TileLayer)
* @param clipGeoJson GeoJSON
*/
private applyMapMask(rasterLayer: TileLayer, clipGeoJson: any): void {
if (!rasterLayer || !clipGeoJson) return;
// 1. 解析 GeoJSON
const features = new GeoJSON().readFeatures(clipGeoJson, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
});
// if (!features || features.length === 0) {
// console.warn('裁切数据为空');
// return;
// }
// // ✅ 调试:添加绿线图层
// const debugVectorSource = new VectorSource({ features: features });
// let debugLayer = this.map!.getLayers()
// .getArray()
// .find((l: any) => l.get('isDebugMask'));
// if (debugLayer) {
// this.map!.removeLayer(debugLayer);
// }
// debugLayer = new VectorLayer({
// source: debugVectorSource,
// style: new Style({
// stroke: new Stroke({ color: '#00FF00', width: 2 }),
// fill: new Fill({ color: 'rgba(0, 255, 0, 0.1)' })
// }),
// zIndex: 9999,
// visible: true
// });
// debugLayer.set('isDebugMask', true);
// this.map!.addLayer(debugLayer);
// 移除旧监听器
if (this._maskPrerender) {
rasterLayer.un('prerender', this._maskPrerender);
}
if (this._maskPostrender) {
rasterLayer.un('postrender', this._maskPostrender);
}
const maskPrerender = (event: any) => {
const context = event.context;
if (!context || !this.map) return;
const frameState = event.frameState;
if (!frameState) return;
context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.beginPath();
let hasPath = false;
for (const feature of features) {
const geom: any = feature.getGeometry();
if (!geom) continue;
const type = geom.getType();
if (type === 'Polygon') {
const rings = geom.getCoordinates() as number[][][];
for (const ring of rings) {
// ✅ 传递 frameState 给 drawRing
this.drawRing(context, ring, frameState);
hasPath = true;
}
} else if (type === 'MultiPolygon') {
const polygons = geom.getCoordinates() as number[][][][];
for (const polygonRings of polygons) {
for (const ring of polygonRings) {
// ✅ 传递 frameState 给 drawRing
this.drawRing(context, ring, frameState);
hasPath = true;
}
}
}
}
if (hasPath) {
context.strokeStyle = 'red';
context.lineWidth = 2;
context.stroke();
context.fillStyle = 'rgba(255, 255, 0, 0.2)';
context.fill();
// context.clip();
} else {
}
context.restore();
};
const maskPostrender = (event: any) => {
if (event.context) {
event.context.restore();
}
};
this._maskPrerender = maskPrerender;
this._maskPostrender = maskPostrender;
rasterLayer.on('prerender', this._maskPrerender);
rasterLayer.on('postrender', this._maskPostrender);
rasterLayer.changed();
}
private drawRing(
context: CanvasRenderingContext2D,
ring: number[][],
frameState: any
) {
if (!ring || ring.length === 0) return;
// ✅ 关键:获取当前 Canvas 的像素比(高清屏通常为 2
// frameState.pixelRatio 是 OL 内部使用的像素比
const pixelRatio = frameState.pixelRatio || window.devicePixelRatio || 1;
for (let i = 0; i < ring.length; i++) {
const coord = ring[i];
if (!this.map || !Array.isArray(coord) || typeof coord[0] !== 'number')
continue;
// ✅ 1. 获取相对于地图容器的 CSS 像素坐标
const cssPixel = this.map.getPixelFromCoordinate(
coord as [number, number]
);
if (!cssPixel) continue;
// ✅ 2. 转换为 Canvas 内部物理像素坐标
// 因为我们在 maskPrerender 中执行了 context.setTransform(1, 0, 0, 1, 0, 0);
// 此时 Canvas 的原点是左上角,单位是物理像素。
// 而 getPixelFromCoordinate 返回的是 CSS 像素。
// 所以必须乘以 pixelRatio。
const canvasX = cssPixel[0] * pixelRatio;
const canvasY = cssPixel[1] * pixelRatio;
if (i === 0) {
context.moveTo(canvasX, canvasY);
} else {
context.lineTo(canvasX, canvasY);
}
}
context.closePath();
}
/** /**
* () * ()
*/ */
@ -1206,10 +1383,10 @@ export class MapOl implements MapInterface {
return '面积:' + areaSqKm.toFixed(3) + 'km²'; return '面积:' + areaSqKm.toFixed(3) + 'km²';
} }
mdLayerShowOrHidden(): void { } mdLayerShowOrHidden(): void {}
switchView(): void { } switchView(): void {}
fitBounds(): void { } fitBounds(): void {}
flyTopanto(): void { } flyTopanto(): void {}
/** /**
* *
*/ */
@ -1219,9 +1396,11 @@ export class MapOl implements MapInterface {
// 1. 清除量算相关资源 // 1. 清除量算相关资源
this.removeQueryLayer(); this.removeQueryLayer();
this._maskPrerender = null;
this._maskPostrender = null;
// 2. 清除所有通过 layerRegistry 管理的图层 // 2. 清除所有通过 layerRegistry 管理的图层
if (this.layerRegistry) { if (this.layerRegistry) {
this.layerRegistry.forEach((layer) => { this.layerRegistry.forEach(layer => {
if (this.map && this.map.getLayers().getArray().includes(layer)) { if (this.map && this.map.getLayers().getArray().includes(layer)) {
this.map.removeLayer(layer); this.map.removeLayer(layer);
} }
@ -1231,7 +1410,7 @@ export class MapOl implements MapInterface {
// ✅ 3. 清除点图层 Registry // ✅ 3. 清除点图层 Registry
if (this.pointLayerRegistry) { if (this.pointLayerRegistry) {
this.pointLayerRegistry.forEach((layer) => { this.pointLayerRegistry.forEach(layer => {
if (this.map && this.map.getLayers().getArray().includes(layer)) { if (this.map && this.map.getLayers().getArray().includes(layer)) {
this.map.removeLayer(layer); this.map.removeLayer(layer);
} }

View File

@ -4,7 +4,7 @@ import { useTagsViewStore } from "@/store/modules/tagsView";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import MapModal from "@/components/MapModal/index.vue"; import MapModal from "@/components/MapModal/index.vue";
import { useModelStore } from "@/store/modules/model"; import { useModelStore } from "@/store/modules/model";
// import GisView from "@/components/gis/GisView.vue"; import GisView from "@/components/gis/GisView.vue";
const modelStore = useModelStore(); const modelStore = useModelStore();
@ -29,7 +29,6 @@ const routeKey = computed(() => router.path + Math.random());
<MapModal <MapModal
v-model:visible="modelStore.modalVisible" v-model:visible="modelStore.modalVisible"
v-model:active-key="modelStore.currentTabKey"
:title="modelStore.title" :title="modelStore.title"
:tabs-config="modelStore.tabList" :tabs-config="modelStore.tabList"
/> />

View File

@ -9,7 +9,27 @@ NProgress.configure({ showSpinner: false });
const permissionStore = usePermissionStoreHook(); const permissionStore = usePermissionStoreHook();
// 白名单路由 // 白名单路由
const whiteList = ['/login','/register']; //login const whiteList = ['/login', '/register']; //login
// ✅ 新增:递归标准化路由路径,确保所有 path 以 '/' 开头
function normalizeRoutes(routes: any[]): any[] {
return routes.map(route => {
// 创建副本以避免直接修改原始数据(可选,视具体需求而定)
const normalizedRoute = { ...route };
// 修正当前路由的 path
if (normalizedRoute.path && !normalizedRoute.path.startsWith('/')) {
normalizedRoute.path = `/${normalizedRoute.path}`;
}
// 递归修正子路由
if (normalizedRoute.children && normalizedRoute.children.length > 0) {
normalizedRoute.children = normalizeRoutes(normalizedRoute.children);
}
return normalizedRoute;
});
}
// 查找第一个可用路由 // 查找第一个可用路由
function findFirstAvailableRoute(routes: any[]): string | undefined { function findFirstAvailableRoute(routes: any[]): string | undefined {
@ -35,11 +55,11 @@ router.beforeEach(async (to, from, next) => {
if (userStore.Token) { if (userStore.Token) {
// 登录成功,跳转到首页 // 登录成功,跳转到首页
if (to.path === '/login') {//login if (to.path === '/login') {
//login
next({ path: '/' }); next({ path: '/' });
NProgress.done(); NProgress.done();
} else { } else {
const hasGetUserInfo = userStore.roles.length > 0; const hasGetUserInfo = userStore.roles.length > 0;
if (hasGetUserInfo) { if (hasGetUserInfo) {
// 已获取用户信息,检查路由匹配 // 已获取用户信息,检查路由匹配
@ -60,7 +80,11 @@ router.beforeEach(async (to, from, next) => {
} else { } else {
try { try {
const { roles } = await userStore.getInfo(); const { roles } = await userStore.getInfo();
const accessRoutes: RouteRecordRaw[] = await permissionStore.generateRoutes(roles); let accessRoutes: RouteRecordRaw[] =
await permissionStore.generateRoutes(roles);
// ✅ 关键修复:在添加路由前,标准化所有路径
accessRoutes = normalizeRoutes(accessRoutes);
accessRoutes.forEach((route: any) => { accessRoutes.forEach((route: any) => {
router.addRoute(route); router.addRoute(route);
@ -85,7 +109,6 @@ router.beforeEach(async (to, from, next) => {
} }
} }
} }
} else { } else {
// 未登录可以访问白名单页面 // 未登录可以访问白名单页面
if (whiteList.indexOf(to.path) !== -1) { if (whiteList.indexOf(to.path) !== -1) {

View File

@ -15,7 +15,7 @@ const filterAsyncRoutes = (routes: RouteRecordRaw[], roles: string[]) => {
// ✅ 保存原始名称到 meta用于菜单显示 // ✅ 保存原始名称到 meta用于菜单显示
tmp.meta = { tmp.meta = {
...tmp.meta, ...tmp.meta,
title: tmp.name || tmp.menuName, // 原始名称用于显示 title: tmp.name || tmp.menuName // 原始名称用于显示
}; };
// ✅ name 使用路径生成唯一值 // ✅ name 使用路径生成唯一值
tmp.name = tmp.path || tmp.opturl; tmp.name = tmp.path || tmp.opturl;
@ -32,7 +32,7 @@ const filterAsyncRoutes = (routes: RouteRecordRaw[], roles: string[]) => {
tmp.component = modules[`../../views/error-page/404.vue`]; tmp.component = modules[`../../views/error-page/404.vue`];
} }
} }
res.push(tmp) res.push(tmp);
if (tmp.children) { if (tmp.children) {
tmp.children = filterAsyncRoutes(tmp.children, roles); tmp.children = filterAsyncRoutes(tmp.children, roles);
} }
@ -57,7 +57,7 @@ export const usePermissionStore = defineStore('permission', () => {
return new Promise<RouteRecordRaw[]>((resolve, reject) => { return new Promise<RouteRecordRaw[]>((resolve, reject) => {
listRoutes() listRoutes()
.then(response => { .then(response => {
const asyncRoutes :any = response; const asyncRoutes: any = response;
const accessedRoutes = filterAsyncRoutes(asyncRoutes, roles); const accessedRoutes = filterAsyncRoutes(asyncRoutes, roles);
setRoutes(accessedRoutes); setRoutes(accessedRoutes);
resolve(accessedRoutes); resolve(accessedRoutes);

View File

@ -7,7 +7,7 @@ import router from '@/router';
// 创建 axios 实例 // 创建 axios 实例
const service = axios.create({ const service = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API, baseURL: import.meta.env.VITE_APP_BASE_API,
timeout: 300000, // 5分钟 timeout: 15000, // 15秒
headers: { 'Content-Type': 'application/json;charset=utf-8' } headers: { 'Content-Type': 'application/json;charset=utf-8' }
}); });
@ -36,9 +36,9 @@ service.interceptors.response.use(
const { status, msg } = response; const { status, msg } = response;
if (status === 200) { if (status === 200) {
if (response.data.code == 401) { if (response.data.code == 401) {
message.error(response.data.msg||'请求失败'); message.error(response.data.msg || '请求失败');
return; return;
}else if(response.data.code == 1){ } else if (response.data.code == 1) {
message.error(response.data.msg); message.error(response.data.msg);
return; return;
} }
@ -48,7 +48,7 @@ service.interceptors.response.use(
if (response.data instanceof ArrayBuffer) { if (response.data instanceof ArrayBuffer) {
return response; return response;
} }
message.error( msg || '系统出错'); message.error(msg || '系统出错');
return Promise.reject(new Error(msg || 'Error')); return Promise.reject(new Error(msg || 'Error'));
} }
}, },
@ -58,15 +58,15 @@ service.interceptors.response.use(
// token 过期,重新登录 // token 过期,重新登录
if (status === '403') { if (status === '403') {
Modal.confirm({ Modal.confirm({
title: "提示", title: '提示',
content: "当前页面已失效,请重新登录", content: '当前页面已失效,请重新登录',
okText: "确定", okText: '确定',
cancelButtonProps: { disabled: false }, cancelButtonProps: { disabled: false },
onOk: () => { onOk: () => {
localStorage.clear(); localStorage.clear();
router.push('/login'); router.push('/login');
window.location.href = '/'; window.location.href = '/';
}, }
}); });
} else { } else {
message.error(msg || '当前页面已失效'); message.error(msg || '当前页面已失效');

View File

@ -34,7 +34,7 @@ const showMapModal = () => {
}; };
const showMapModal1 = () => { const showMapModal1 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "ENG"; modelStore.params.sttp = "zh";
modelStore.title = "三峡222 详情信息"; modelStore.title = "三峡222 详情信息";
modelStore.currentTabKey = "basicInfo"; modelStore.currentTabKey = "basicInfo";
modelStore.isBasicEdit = false; modelStore.isBasicEdit = false;

View File

@ -723,6 +723,7 @@ const fileChange = (file: File) => {
const formData = new FormData(); const formData = new FormData();
formData.append("file", file); formData.append("file", file);
await importFishZip(formData); await importFishZip(formData);
if (visible.value) importBtn();
}); });
}; };
// //

File diff suppressed because it is too large Load Diff