You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

636 lines
22 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!--
智能井位推荐参数设置
author: RYG
date: 2025年6月25日09:37:38
-->
<template>
<div class="scrollable-form">
<el-form v-model="propertyParam.wellParamSettings" label-position="right" label-width="100px">
<!-- 标题设置 -->
<div name="wellParamSettings" class="well-param">
<el-divider content-position="left">井平台参数设置</el-divider>
<el-form-item label="断裂图件" label-position="right" class="well-param-item">
<el-select v-model="propertyParam.wellParamSettings.selectedOption" placeholder="请选择断裂文件"
class="well-param-input">
<el-option v-for="item in fractureFileData" :key="item.MapID" :label="item.MapName" :value="item.MapID"
@click="handleOptionClick(item)"></el-option>
</el-select>
</el-form-item>
<el-form-item label="边界图层" label-position="right" class="well-param-item">
<el-input v-model="propertyParam.wellParamSettings.boundaryLayer" placeholder="选择边界图层"
class="well-param-input" @click="showBoundaryLayerData"></el-input>
</el-form-item>
<el-form-item label="断层图层" label-position="right" class="well-param-item">
<el-input v-model="propertyParam.wellParamSettings.faultLayer" placeholder="选择断层图层" class="well-param-input"
@click="showFractureLayerData"></el-input>
</el-form-item>
<el-form-item label="井名" label-position="right" class="well-param-item">
<el-input v-model="propertyParam.wellParamSettings.WellNamePrefix" placeholder="输入井名"
class="well-param-input"></el-input>
</el-form-item>
<el-form-item label="井支数" class="well-param-item">
<el-input-number v-model="propertyParam.wellParamSettings.BranchCount" placeholder="井支数"
class="well-param-input"></el-input-number>
</el-form-item>
<el-form-item label="靶前距" class="well-param-item">
<el-input-number v-model="propertyParam.wellParamSettings.BranchOffset" placeholder="靶前距"
class="well-param-input"></el-input-number>
</el-form-item>
<el-form-item label="水平段长度" class="well-param-item">
<el-input-number v-model="propertyParam.wellParamSettings.BranchLength" placeholder="水平段长度"
class="well-param-input"></el-input-number>
</el-form-item>
<el-form-item label="井支间距" class="well-param-item">
<el-input-number v-model="propertyParam.wellParamSettings.BranchSpace" placeholder="井支间距"
class="well-param-input"></el-input-number>
</el-form-item>
<div class="other-form-item-nolabel">
<el-checkbox v-model="propertyParam.wellParamSettings.DeploySide2">双侧布井</el-checkbox><el-checkbox
v-model="propertyParam.wellParamSettings.DeploySide1">单侧布井</el-checkbox>
</div>
<div class="other-form-item-nolabel">
<el-checkbox v-model="propertyParam.wellParamSettings.DeployAgain">二次布井</el-checkbox>
</div>
</div>
</el-form>
<el-form label-width="100px" :model="propertyParam.calcParamSettings">
<!-- 坐标轴设置 -->
<div name="calcParamSettings" class="well-param">
<el-divider content-position="left">计算参数设置</el-divider>
<el-form-item label="井平台间距" class="well-param-item">
<el-input-number v-model="propertyParam.calcParamSettings.WellsSpace" placeholder="井平台间距"
class="well-param-input"></el-input-number>
</el-form-item>
<el-form-item label="突变率" class="well-param-item">
<el-input-number v-model="propertyParam.calcParamSettings.MutationRate" placeholder="突变率" :min="0.1"
:max="0.9" class="well-param-input" :step="0.1"></el-input-number>
</el-form-item>
<el-form-item label="旋转次数" class="well-param-item">
<el-input-number v-model="propertyParam.calcParamSettings.Rotations" placeholder="旋转次数"
class="well-param-input"></el-input-number>
</el-form-item>
<el-form-item label="角度范围" class="well-param-item">
<el-input v-model="propertyParam.calcParamSettings.AngleStart" placeholder="角度范围最小值" class="well-param-input"
style="width: 60px"></el-input>
&nbsp; ~ &nbsp;
<el-input v-model="propertyParam.calcParamSettings.AngleEnd" placeholder="角度范围最大值" class="well-param-input"
style="width: 60px"></el-input>
</el-form-item>
<el-form-item label="指定角度" class="well-param-item">
<div class="other-form-item">
<el-checkbox v-model="propertyParam.calcParamSettings.SpecifyAngles" placeholder="指定角度"></el-checkbox>
<el-input v-model="propertyParam.calcParamSettings.SpeciaAngles" placeholder="指定角度范围"
:disabled="!propertyParam.calcParamSettings.SpecifyAngles" class="well-param-input"></el-input>
</div>
</el-form-item>
<el-form-item label="忽略小断裂" class="well-param-item">
<div class="other-form-item">
<el-checkbox class="left-label" v-model="propertyParam.calcParamSettings.IgnoreMiniFault"
placeholder="忽略小断裂"></el-checkbox>
<el-input v-model="propertyParam.calcParamSettings.MiniFaultLength" placeholder="断裂值"
:disabled="!propertyParam.calcParamSettings.IgnoreMiniFault" class="well-param-input"
style="width: 80px"></el-input>
</div>
</el-form-item>
</div>
</el-form>
<div class="button-container">
<el-button type="primary" @click="handleStartCalc" :disabled="smartWellButton">计算</el-button>
<el-button type="primary" @click="handleStopCalc(true)" :disabled="smartWellButtonStop"></el-button>
</div>
<el-dialog v-model="showLayer" title="请选择层位数据" style="width: 270px; height: 600px; z-index: 30" @close="handleClose"
:close-on-click-modal="false">
<div class="img-layer">
<ClientOnly>
<LayerTree :isPopup="true" class="popup-tree" :show-oper="true" :token-key="currentTokenKey" />
</ClientOnly>
</div>
</el-dialog>
<ProgressTracker ref="progressRef" v-model="progressVisible" title="计算进度" :initialProgress="currentProgress"
:message="progressMessage" @complete="onComplete" @manual-close="onManualClose" />
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from "vue";
import {
fractureFileList,
startSmartWellCalc,
stopSmartWellCalc,
getWellRecommend
} from "@/services/wellRecommandService";
import { emitter } from "~/utils/eventBus";
import { checkEmpty } from "@/utils/objHelper";
import { EMIT_COMMAND } from '~/utils/commandTypes';
import { useSignalR } from "~/composables/useSignalR";
import { STORAGE_KEYS } from "~/utils/storageKeys"
// 当前页图件token的 key
const currentTokenKey = STORAGE_KEYS.WELL_RECOMMAND_TOKEN;
// 消息提示(自动隐藏)
const { $toastMessage } = useNuxtApp();
const { connect, connectionId, sigMsg, sendMessage, on } = useSignalR();
// 进度条显示状态
const progressVisible = ref(false);
const progressRef = ref(null);
const currentToken = computed(() => localStorage.getItem(currentTokenKey));
// 当前进度
const currentProgress = ref(0);
// 当前进度的消息
const progressMessage = ref('');
// 任务是否已经开始,用于按钮状态控制、任务状态监听
const taskStarted = ref(false);
// 任务ID
const taskId = ref("");
const emit = defineEmits(['openFile'])
// 配置参数
const propertyParam = reactive({
// 井平台参数设置
wellParamSettings: {
selectedOption: "",
fractureFile: "",
boundaryLayer: "",
faultLayer: "",
WellNamePrefix: "井",
BranchCount: 6,
BranchOffset: 500,
BranchLength: 1800,
BranchSpace: 300,
DeploySide2: true,
DeploySide1: true,
DeployAgain: false,
},
// 计算参数设置
calcParamSettings: {
WellsSpace: 500,
MutationRate: 0.5, // 0.1-0.9之间
Rotations: 8,
AngleStart: 30,
AngleEnd: 90,
SpecifyAngles: false,
SpeciaAngles: ["0", "0", "90", "0", "0", "270", "180", "180", "180"],
IgnoreMiniFault: true,
MiniFaultLength: 1000,
},
});
// 图层顶层
const boundaryLayerData = reactive([
{
id: 0,
parentId: 0,
name: "图层",
status: 0,
children: [],
},
]);
// 计算按钮状态
const smartWellButton = computed(() => taskStarted.value);
// 停止按钮状态
const smartWellButtonStop = computed(() => !taskStarted.value);
// 二次布井时用到的数据Id
const DeployAgainId = ref('');
const fractureFileData = ref([]);
/** 标识选择的是边界还是断层0边界1断层 */
const inputType = ref(-1);
// 图层显示切换属性
const showLayer = ref(false);
watchEffect(() => {
if (!sigMsg.value) {
return;
}
const msg = JSON.parse(sigMsg.value);
const prog = msg.progress;
const smsg = msg.msg;
currentProgress.value = prog;
progressMessage.value = smsg;
updateCalcInfo(prog, smsg, true);
emitMsg({
type: "calcRedraw",
cmdID: currentTokenKey,
data: JSON.stringify({ msg: '重新绘制' }),
});
emitRefresh();
});
// 处理选择断裂图件
const handleOptionClick = (item) => {
emitter.emit(EMIT_COMMAND.SOURCE_CHANGED);
// emitMsg({
// type: EMIT_COMMAND.OPEN_FILE,
// cmdID: currentTokenKey,
// data: JSON.stringify({ fileName: item.MapName }),
// });
// doOpenFile(item.MapName, currentTokenKey);
console.log("打开图件:handleOptionClick=", item.MapName)
emit('openFile', item.MapName);
// 如果选择了断裂图件就表示要计算新的
// if (DeployAgainId.value === 0) {
propertyParam.wellParamSettings.fractureFile = item.MapName;
// 清空之前选择的图层数据
boundaryLayerData[0].children = [];
propertyParam.wellParamSettings.boundaryLayer = "";
propertyParam.wellParamSettings.faultLayer = "";
// }
};
// 显示边界图层数据的逻辑
const showBoundaryLayerData = () => {
if (!propertyParam.wellParamSettings.selectedOption) {
$toastMessage.warning("您还没有选择断裂分布图!");
return;
}
// 检查boundaryLayerData是否正确定义
if (!boundaryLayerData || !boundaryLayerData[0] || !boundaryLayerData[0].children) {
console.error("boundaryLayerData结构不正确");
$toastMessage.error("图层数据结构初始化失败!");
return;
}
inputType.value = 0;
// 显示选择框
showLayer.value = true;
};
// 显示断层图层数据的逻辑
const showFractureLayerData = () => {
if (!propertyParam.wellParamSettings.selectedOption) {
$toastMessage.warning("您还没有选择断裂分布图!");
return;
}
inputType.value = 1;
// 显示选择框
showLayer.value = true;
};
// 发送计算命令
const handleStartCalc = async () => {
try {
// 检查断裂分布图选择
let selectedChunk = null;
if (propertyParam.wellParamSettings.DeployAgain) {
// 是二次布井
selectedChunk = propertyParam.wellParamSettings.selectedOption;
} else {
let selectedValue = fractureFileData.value.find(
(chunk) => chunk.MapID === propertyParam.wellParamSettings.selectedOption
);
selectedChunk = selectedValue?.MapName;
if (checkEmpty(selectedChunk)) {
$toastMessage.warning("您还没有选择断裂分布图!");
return;
}
}
if (!selectedChunk) {
$toastMessage.warning("您还没有选择断裂分布图!");
return;
}
if (!connectionId.value) {
$toastMessage.warning("实时消息连接未建立,请刷新页面重试!");
return;
}
// 检查必要参数
if (checkEmpty(propertyParam.wellParamSettings.boundaryLayer)) {
$toastMessage.warning("请选择边界图层!");
return;
}
if (checkEmpty(propertyParam.wellParamSettings.faultLayer)) {
$toastMessage.warning("请选择断层图层!");
return;
}
// 修改按钮状态
taskStarted.value = true;
// 组装计算参数
const smartWellParam = {
DeployAgainId: DeployAgainId.value,
clientId: currentToken.value,
drawerId: currentToken.value,
connectionId: connectionId.value,
wellParamSettings: {
fractureFile: selectedChunk || propertyParam.wellParamSettings.selectedOption,
boundaryLayer: propertyParam.wellParamSettings.boundaryLayer,
faultLayer: propertyParam.wellParamSettings.faultLayer,
WellNamePrefix: propertyParam.wellParamSettings.WellNamePrefix,
BranchCount: parseInt(propertyParam.wellParamSettings.BranchCount) || 6,
BranchOffset: parseInt(propertyParam.wellParamSettings.BranchOffset) || 500,
BranchLength: parseInt(propertyParam.wellParamSettings.BranchLength) || 1800,
BranchSpace: parseInt(propertyParam.wellParamSettings.BranchSpace) || 300,
DeploySide2: propertyParam.wellParamSettings.DeploySide2,
DeploySide1: propertyParam.wellParamSettings.DeploySide1,
DeployAgain: propertyParam.wellParamSettings.DeployAgain,
},
calcParamSettings: {
WellsSpace: parseInt(propertyParam.calcParamSettings.WellsSpace) || 500,
MutationRate: parseFloat(propertyParam.calcParamSettings.MutationRate) || 0.5,
Rotations: parseInt(propertyParam.calcParamSettings.Rotations) || 8,
AngleStart: parseInt(propertyParam.calcParamSettings.AngleStart) || 30,
AngleEnd: parseInt(propertyParam.calcParamSettings.AngleEnd) || 90,
SpecifyAngles: propertyParam.calcParamSettings.SpecifyAngles,
SpeciaAngles: propertyParam.calcParamSettings.SpecifyAngles ? (propertyParam.calcParamSettings.SpeciaAngles ? [propertyParam.calcParamSettings.SpeciaAngles] : []) : [],
IgnoreMiniFault: propertyParam.calcParamSettings.IgnoreMiniFault,
MiniFaultLength:
parseInt(propertyParam.calcParamSettings.MiniFaultLength) || 1000,
},
};
progressVisible.value = true;
const response = await startSmartWellCalc(smartWellParam);
if (!response) {
taskStarted.value = false;
taskId.value = "";
$toastMessage.error("智能布井失败: 服务器未返回任务ID");
progressVisible.value = false;
return;
}
taskId.value = response;
updateCalcInfo(0, "正在初始化", true);
} catch (error) {
console.error("智能布井出错:", error);
taskId.value = null;
$toastMessage.error(
`智能布井失败: ${error.response?.data?.message || error.message || "未知错误"}`
);
localStorage.removeItem("currentTaskId");
progressVisible.value = false;
progressMessage.value = '';
}
};
const updateCalcInfo = (progress, msg, isRunning) => {
localStorage.setItem(
"currentTaskId",
JSON.stringify({
taskId: taskId.value,
progress: progress,
message: msg,
isRunning: isRunning,
})
);
}
// 手动关闭进度条
const onManualClose = async () => {
await handleStopCalc(false);
}
// 停止任务处理
const handleStopCalc = async (closeProgress = true) => {
// 停止计算的逻辑
try {
if (taskId.value && taskStarted.value) {
const response = await stopSmartWellCalc(taskId.value);
if (response) {
$toastMessage.info("成功停止计算任务");
// emitRefresh();
// localStorage.removeItem("currentTaskId");
} else {
$toastMessage.warning("停止任务失败");
}
}
} catch (error) {
console.error("停止错误:", error);
} finally {
taskId.value = null;
// 更新本地存储
updateCalcInfo(0, "任务已停止", false);
// 加载断裂图件
await getFractureFileList();
if (closeProgress && progressRef.value) {
progressRef.value.close();
}
// progressVisible.value = false;
taskStarted.value = false;
emitRefresh();
emitMsg({
type: "calcRedraw",
cmdID: currentTokenKey,
data: JSON.stringify({ msg: '重新绘制' }),
});
}
};
const emitRefresh = () => {
emitter.emit(EMIT_COMMAND.REFRESH_RESULT);
};
const emitMsg = (data) => {
// console.log("emitMsg", data);
emitter.emit(EMIT_COMMAND.EVT_TYPE, data);
};
onMounted(async () => {
// 加载断裂图件
await getFractureFileList();
listenEmitter();
});
// 监听图层选择
const listenEmitter = () => {
emitter.on(EMIT_COMMAND.SELECTED_LAYER, (data) => {
handleClose();
if (checkEmpty(data)) {
$toastMessage.warning("请选择图层!");
return;
}
switch (inputType.value) {
case 0:
propertyParam.wellParamSettings.boundaryLayer = data;
break;
case 1:
propertyParam.wellParamSettings.faultLayer = data;
break;
}
});
// // 二次布井事件
// emitter.on("reCalc", async (data) => {
// try {
// const response = await getWellRecommend(data.Id);
// if (!response) {
// $toastMessage.error("获取井推荐参数失败!");
// return;
// }
// DeployAgainId.value = data.Id;
// propertyParam.wellParamSettings.selectedOption = response.OutGraphicFile;
// nextTick();
// propertyParam.wellParamSettings.boundaryLayer = response.Boundary_Layer;
// propertyParam.wellParamSettings.faultLayer = response.Fault_Layer;
// propertyParam.wellParamSettings.WellNamePrefix = response.Well_Name;
// propertyParam.wellParamSettings.BranchCount = response.Well_Nums;
// propertyParam.wellParamSettings.BranchOffset = response.Target_Space;
// propertyParam.wellParamSettings.BranchLength = response.Horizon_Length;
// propertyParam.wellParamSettings.BranchSpace = response.WellBranchSpace;
// propertyParam.wellParamSettings.DeploySide2 = response.DoubleWell;
// propertyParam.wellParamSettings.DeploySide1 = response.SingleWell;
// propertyParam.wellParamSettings.DeployAgain = true; // 标记二次布井
// propertyParam.calcParamSettings.WellsSpace = response.WellSpace;
// propertyParam.calcParamSettings.MutationRate = response.MutationRate;
// propertyParam.calcParamSettings.Rotations = response.RotationTimes;
// propertyParam.calcParamSettings.AngleStart = response.AngularRangeMin;
// propertyParam.calcParamSettings.AngleEnd = response.AngularRangeMax;
// propertyParam.calcParamSettings.SpecifyAngles = response.IsAngleRange;
// // this.calcParamSettings.SpeciaAngles = response.AngleRangeValue; // 角度范围值
// propertyParam.calcParamSettings.IgnoreMiniFault = response.IsSmallFracture;
// propertyParam.calcParamSettings.MiniFaultLength = response.SmallFractureValue;
// // 调用二次布井方法
// await handleStartCalc();
// } catch (error) {
// console.error("获取智能布井计算参数时出错:", error);
// $toastMessage.error("获取智能布井计算参数出错了");
// }
// });
// 计算参数
emitter.on(EMIT_COMMAND.CALC_PROPERTY, async (data) => {
const response = await getWellRecommend(data.Id);
if (!response) {
$toastMessage.error("获取井推荐参数失败!");
return;
}
DeployAgainId.value = data.Id;
propertyParam.wellParamSettings.selectedOption = response.Fracture_FileName;
propertyParam.wellParamSettings.boundaryLayer = data.Boundary_Layer;
propertyParam.wellParamSettings.faultLayer = data.Fault_Layer;
propertyParam.wellParamSettings.WellNamePrefix = data.Well_Name;
propertyParam.wellParamSettings.BranchCount = data.Well_Nums;
propertyParam.wellParamSettings.BranchOffset = data.Target_Space;
propertyParam.wellParamSettings.BranchLength = data.Horizon_Length;
propertyParam.wellParamSettings.BranchSpace = data.WellBranchSpace;
propertyParam.wellParamSettings.DeploySide2 = data.DoubleWell;
propertyParam.wellParamSettings.DeploySide1 = data.SingleWell;
propertyParam.wellParamSettings.DeployAgain = false; // 标记二次布井
propertyParam.calcParamSettings.WellsSpace = data.WellSpace;
propertyParam.calcParamSettings.MutationRate = data.MutationRate;
propertyParam.calcParamSettings.Rotations = data.RotationTimes;
propertyParam.calcParamSettings.AngleStart = data.AngularRangeMin;
propertyParam.calcParamSettings.AngleEnd = data.AngularRangeMax;
propertyParam.calcParamSettings.SpecifyAngles = data.IsAngleRange;
propertyParam.calcParamSettings.SpeciaAngles = data.AngleRangeValue; // 角度范围值
propertyParam.calcParamSettings.IgnoreMiniFault = data.IsSmallFracture;
propertyParam.calcParamSettings.MiniFaultLength = data.SmallFractureValue;
});
};
onBeforeUnmount(() => {
emitter.off(EMIT_COMMAND.SELECTED_LAYER);
emitter.off(EMIT_COMMAND.CALC_PROPERTY);
handleStopCalc(true);
});
const handleClose = () => {
showLayer.value = false;
};
// 获取断裂图件
const getFractureFileList = async () => {
let response = await fractureFileList();
if (response) {
fractureFileData.value = response;
}
};
const onComplete = () => {
};
</script>
<style scoped>
.scrollable-form {
/* max-height: 900px; */
min-height: 500px;
width: 290px;
height: 100%;
}
.well-param-item {
height: 25px;
}
.well-param-input {
width: 140px;
height: 25px;
}
.button-container {
display: flex;
justify-content: flex-end;
margin-right: 30px;
margin-bottom: 20px;
}
.other-form-item {
display: inline-flex;
flex-direction: row;
justify-content: flex-start;
gap: 10px;
}
.other-form-item-nolabel {
display: inline-flex;
flex-direction: row;
padding-left: 65px;
justify-content: flex-start;
}
.img-layer {
height: 500px;
background: #ccc;
border: 1px solid #333;
overflow: hidden;
}
.popup-tree {
height: 500px;
width: 100%;
}
</style>