进度填报单选优化,项目列表地图功能修正

This commit is contained in:
Teo
2025-06-03 19:57:53 +08:00
parent 6758437892
commit 80c9d517ab
4 changed files with 301 additions and 55 deletions

View File

@ -22,7 +22,7 @@
<p
v-for="(item, index) in selectLayer"
class="pl-xl border-rd pr p-3 w-111 mr-1 bg-#909399 flex items-center cursor-pointer justify-between"
@click="delLayer(index)"
@click="delLayer(index, item.option)"
>
{{ item.location.name + '被选中为' + item.option }}
<el-icon>
@ -30,35 +30,27 @@
</el-icon>
</p>
</div>
<el-form-item label="类型" class="items-center">
<!-- <el-form-item label="类型" class="items-center">
<el-radio-group v-model="layerType">
<el-radio value="1" size="large">光伏板</el-radio>
<el-radio value="2" size="large">桩点/支架</el-radio>
<el-radio value="3" size="large">方阵</el-radio>
<el-radio value="4" size="large">逆变器</el-radio>
<el-radio value="5" size="large">箱变</el-radio>
<el-radio :value="1" size="large">光伏板</el-radio>
<el-radio :value="2" size="large">桩点/支架</el-radio>
<el-radio :value="3" size="large">方阵</el-radio>
<el-radio :value="4" size="large">逆变器</el-radio>
<el-radio :value="5" size="large">箱变</el-radio>
</el-radio-group>
</el-form-item>
</el-form-item> -->
</div>
<div v-if="isMenuVisible" :style="{ left: menuX + 'px', top: menuY + 'px' }" class="fixed bg-white shadow-md rounded-md overflow-hidden">
<ul class="py-1 pl-0">
<li class="px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 cursor-pointer" @click="handleMenuItemClick('光伏板')">
<i class="fa-solid fa-check mr-2"></i>光伏板
<li
v-for="(item, index) in layerTypeList"
class="px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 cursor-pointer"
@click="handleMenuItemClick(item, index + 1)"
>
<i class="fa-solid fa-check mr-2"></i>{{ item }}
</li>
<li class="px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 cursor-pointer" @click="handleMenuItemClick('桩点/支架')">
<i class="fa-solid fa-times mr-2"></i>桩点/支架
</li>
<li class="px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 cursor-pointer" @click="handleMenuItemClick('方阵')">
<i class="fa-solid fa-times mr-2"></i>方阵
</li>
<li class="px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 cursor-pointer" @click="handleMenuItemClick('逆变器')">
<i class="fa-solid fa-times mr-2"></i>逆变器
</li>
<li class="px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 cursor-pointer" @click="handleMenuItemClick('箱变')">
<i class="fa-solid fa-times mr-2"></i>箱变
</li>
<li class="px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 cursor-pointer" @click="handleMenuItemClick('名称')">
<li class="px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 cursor-pointer" @click="handleMenuItemClick('名称', null)">
<i class="fa-solid fa-times mr-2"></i>名称
</li>
</ul>
@ -98,6 +90,7 @@ const props = defineProps({
});
const treeData = ref<any>([]);
const layerType = ref(null);
const layerTypeList = ref(['光伏板', '桩点/支架', '方阵', '逆变器', '箱变']);
const contextMenu = ref(null);
const selectLayer = ref([]);
const treeRef = ref<TreeInstance>();
@ -325,7 +318,7 @@ const showMenu = (event: MouseEvent, data) => {
};
// 处理菜单项点击事件的方法
const handleMenuItemClick = (option: string) => {
const handleMenuItemClick = (option: string, index: number) => {
isMenuVisible.value = false;
if (selectLayer.value.some((item) => item.location.name === contextMenu.value.name)) {
@ -335,14 +328,17 @@ const handleMenuItemClick = (option: string) => {
if (option !== '名称' && option !== '箱变') return proxy?.$modal.msgError('只能选择一个类型');
}
selectLayer.value.push({ location: contextMenu.value, option });
console.log('selectLayer.value', selectLayer.value);
layerType.value = index ? index : layerType.value; // 设置 layerType 为对应的索引值
emit('handleCheckChange', selectLayer.value);
};
//删除菜单
const delLayer = (index) => {
const delLayer = (index, option) => {
selectLayer.value.splice(index, 1);
if (option != '名称') {
if (selectLayer.value.every((item) => item.option == '名称')) layerType.value = null;
}
emit('handleCheckChange', selectLayer.value);
};
@ -478,9 +474,7 @@ const addFacilities = async () => {
const reset = () => {
selectLayer.value = [];
treeRef.value?.setCheckedKeys([]);
for (const key in layerData) {
map.removeLayer(layerData[key]);
}
sharedSource.clear(); // 清空共享 source 中的所有要素
layerType.value = null;
};

View File

@ -1,12 +1,12 @@
<template>
<div class="header flex justify-end">
<el-form :model="queryParams" ref="form" label-width="80px" inline class="flex items-center">
<el-form-item label="请选择项目:" prop="pid" label-width="100">
<el-form-item label="请选择项目:" prop="pid" label-width="100" style="margin-bottom: 0">
<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-select>
</el-form-item>
<el-form-item label="请选择方阵:" prop="pid" label-width="100">
<el-form-item label="请选择方阵:" prop="pid" label-width="100" style="margin-bottom: 0">
<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-select>
@ -19,7 +19,6 @@
style="max-width: 600px"
:data="progressCategoryList"
ref="treeRef"
show-checkbox
@check-change="handleCheckChange"
:props="treeProps"
:load="loadNode"
@ -27,10 +26,12 @@
lazy
@node-collapse="closeNode"
@node-expand="openNode"
:render-content="renderContent"
check-strictly
/>
</div>
<div class="submit">
<el-button type="primary" size="default" @click="submit">提交</el-button>
<el-button type="primary" size="default" @click="submit" :loading="loading">提交</el-button>
</div>
</template>
@ -45,11 +46,13 @@ import { useUserStoreHook } from '@/store/modules/user';
import { getProjectSquare, listProgressCategory, addDaily, workScheduleListPosition } from '@/api/progress/plan';
import { ProgressCategoryVO, progressPlanDetailForm } from '@/api/progress/plan/types';
import { Circle, Fill, Stroke, Style, Text } from 'ol/style';
import { defaults as defaultInteractions } from 'ol/interaction';
import Feature from 'ol/Feature';
import { Point, Polygon } from 'ol/geom';
import VectorSource from 'ol/source/Vector';
import VectorLayer from 'ol/layer/Vector';
import Node from 'element-plus/es/components/tree/src/model/node.mjs';
import { ElCheckbox } from 'element-plus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
// 获取用户 store
@ -96,20 +99,14 @@ const handleSelect = (projectId: string) => {
/** 进度类别树选中事件 */
const handleCheckChange = (data: any, checked: boolean, indeterminate: boolean) => {
const node: Node | undefined = treeRef.value?.getNode(data.id);
if (node && node.level === 3) {
console.log('第三级节点被选中:', data, '选中状态:', checked);
}
if (!node || node.level !== 3 || !checked) return;
if (!checked) return (submitForm.value.id = ''); // 只处理第三级节点的选中事件
const parent = node.parent;
if (!parent) return;
// 遍历兄弟节点,取消选中除当前节点之外的其他第三级节点
parent.childNodes.forEach((sibling: Node) => {
if (sibling !== node) {
treeRef.value.setChecked(sibling.data.id, false, false);
}
});
//消除所有节点的选中状态
treeRef.value.setCheckedKeys([], false);
// 设置当前点击项为选中
treeRef.value.setChecked(data.id, true, false);
submitForm.value.id = data.id; // 设置提交表单的id
};
@ -172,9 +169,20 @@ const loadNode = async (node: any, resolve: (data: any[]) => void) => {
/** 提交按钮点击事件 */
const submit = () => {
console.log('sunbmitForm', submitForm.value);
const { finishedDetailIdList, id } = submitForm.value;
if (!id || finishedDetailIdList.length === 0) return proxy?.$modal.msgWarning('请选择图层以及日期');
loading.value = true;
addDaily(submitForm.value)
.then(() => {
proxy?.$modal.msgSuccess('提交成功');
const scale = Math.max(map.getView().getZoom() / 10, 1); // 获取当前缩放比例
sharedSource.getFeatures().forEach((feature) => {
if (feature.get('highlighted')) {
feature.setStyle(successStyle(feature.get('name'), scale)); // 转为成功样式
feature.set('highlighted', false); // 重置高亮状态
feature.set('status', '2'); // 设置为完成状态
}
});
resetTreeAndMap();
})
.catch((error) => {
@ -186,6 +194,8 @@ const submit = () => {
const resetTreeAndMap = () => {
// 重置树形结构选中状态
treeRef.value?.setCheckedKeys([]);
//取消加载状态
loading.value = false;
// 清除地图上的所有高亮
const scale = Math.max(map.getView().getZoom() / 10, 1); // 获取当前缩放比例
sharedSource.getFeatures().forEach((feature) => {
@ -205,6 +215,22 @@ const handleChange = (value: number) => {
getList();
};
//限定部分节点能选择
const renderContent = (context, { node }) => {
if (node.level === 3) {
return h('span', { class: 'custom-tree-node' }, [
h(ElCheckbox, {
modelValue: node.checked,
'onUpdate:modelValue': (val) => node.setChecked(val),
style: 'margin-right: 8px;margin-left: -20px;'
}),
h('span', node.label)
]);
} else {
return h('span', node.label);
}
};
//切换项目重置方阵
const resetMatrix = () => {
matrixValue.value = undefined;
@ -271,26 +297,29 @@ const initOLMap = () => {
zoom: false,
rotate: false,
attribution: false
}),
interactions: defaultInteractions({
doubleClickZoom: false // 禁用双击缩放
})
});
map.on('click', (e: any) => {
const zoom = map.getView().getZoom();
const scale = Math.max(zoom / 10, 1); // 缩放比例,根据需要调整公式
map.forEachFeatureAtPixel(e.pixel, (feature: Feature) => {
if (feature.get('status') === '2') return; // 如果是完成状态,直接返回
const isHighlighted = feature.get('highlighted') === true;
const geomType = feature.getGeometry().getType();
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;
}
if (geomType === 'Polygon') {
feature.setStyle(highlightStyle(feature.get('name'), scale));
feature.set('highlighted', true);
submitForm.value.finishedDetailIdList.push(feature.get('id')); // 添加到已完成列表
}
});
});
map.getView().on('change:resolution', () => {
@ -455,10 +484,13 @@ onMounted(() => {
z-index: 1;
}
.header {
height: 90px;
height: 70px;
width: 100%;
position: absolute;
z-index: 2;
background: rgba(255, 255, 255, 0.2); /* 半透明白色 */
backdrop-filter: blur(10px); /* 背景模糊 */
-webkit-backdrop-filter: blur(10px); /* 兼容 Safari */
}
.aside {
position: absolute;
@ -476,4 +508,8 @@ onMounted(() => {
right: 70px;
z-index: 3;
}
.custom-tree-node {
display: flex;
align-items: center;
}
</style>

View File

@ -45,7 +45,17 @@
<el-table v-loading="loading" :data="projectList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" 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">
<template #default="scope">
<el-link
:type="scope.row.designId ? 'primary' : 'default'"
:disabled="!scope.row.designId"
@click="handleOpenLayer(scope.row)"
v-loading.fullscreen.lock="fullscreenLoading"
>{{ scope.row.projectName }}</el-link
>
</template>
</el-table-column>
<el-table-column label="项目简称" align="center" prop="shortName" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
@ -69,7 +79,7 @@
<el-table-column label="开工时间" align="center" prop="onStreamTime" width="120" />
<el-table-column label="打卡范围" align="center" prop="punchRange" />
<el-table-column label="设计总量" align="center" prop="designTotal" />
<el-table-column label="是否上传DXF" align="center" prop="designId" width="140">
<!-- <el-table-column label="是否上传DXF" align="center" prop="designId" width="140">
<template #default="scope">
<el-link
:type="scope.row.designId ? 'primary' : 'default'"
@ -79,7 +89,7 @@
>{{ scope.row.designId ? '已上传' : '未上传' }}</el-link
>
</template>
</el-table-column>
</el-table-column> -->
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180" />
<el-table-column fixed="right" label="操作" align="center" class-name="small-padding fixed-width" width="400">

File diff suppressed because one or more lines are too long