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.

623 lines
21 KiB
Vue

1 month ago
<!--
智能井位推荐参数设置
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>
1 month ago
<el-button type="primary" @click="handleStopCalc" :disabled="smartWellButtonStop">停止</el-button>
1 month ago
</div>
1 month ago
<el-dialog v-model="showLayer" title="请选择层位数据" style="width: 270px; height: 700px; z-index: 1000"
@close="handleClose">
1 month ago
<div class="img-layer">
<ClientOnly>
1 month ago
<LayerTree :isPopup="true" class="popup-tree" />
1 month ago
</ClientOnly>
</div>
</el-dialog>
1 month ago
<ProgressBar :is-visible="progressVisible" :progress="currentProgress" :message="progressMessage"
@hide="progressVisible = false" />
1 month ago
</div>
</template>
<script setup>
1 month ago
import { ref, onMounted, onBeforeUnmount } from "vue";
1 month ago
import {
fractureFileList,
startSmartWellCalc,
stopSmartWellCalc,
getWellRecommend
} from "@/services/wellRecommandService";
import { emitter } from "~/utils/eventBus";
import { checkEmpty } from "@/utils/objHelper";
1 month ago
const { message, status, send } = useWebSocket();
1 month ago
import { useSignalR } from "~/composables/useSignalR";
// 消息提示(自动隐藏)
const { $toastMessage } = useNuxtApp();
const { connect, connectionId, sigMsg, sendMessage, on } = useSignalR();
// 进度条显示状态
const progressVisible = ref(false);
// 当前进度
const currentProgress = ref(0);
// 当前进度的消息
const progressMessage = ref('');
// 任务是否已经开始,用于按钮状态控制、任务状态监听
const taskStarted = ref(false);
// 任务ID
const taskId = ref("");
// 配置参数
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;
}
1 month ago
console.log("得到SignalR消息", sigMsg.value);
1 month ago
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",
data: JSON.stringify({ msg: '重新绘制' }),
});
});
1 month ago
// on("ReceiveProgress", (progress, msg) => {
// console.log('结果:', progress, msg);
// });
1 month ago
// 处理选择断裂图件
const handleOptionClick = (item) => {
1 month ago
console.log("选择的断裂图件:", item.MapName);
emitMsg({
type: "openFile",
data: JSON.stringify({ fileName: item.MapName }),
});
if (DeployAgainId.value === 0) {
propertyParam.wellParamSettings.fractureFile = item.MapName;
1 month ago
1 month ago
// 清空之前选择的图层数据
boundaryLayerData[0].children = [];
propertyParam.wellParamSettings.boundaryLayer = "";
propertyParam.wellParamSettings.faultLayer = "";
}
};
1 month ago
// 显示边界图层数据的逻辑
const showBoundaryLayerData = () => {
1 month ago
console.log("显示边界图层数据");
1 month ago
if (!propertyParam.wellParamSettings.selectedOption) {
1 month ago
$toastMessage.warning("您还没有选择断裂分布图!", 2000);
1 month ago
return;
}
// 检查boundaryLayerData是否正确定义
if (!boundaryLayerData || !boundaryLayerData[0] || !boundaryLayerData[0].children) {
console.error("boundaryLayerData结构不正确");
$toastMessage.error("图层数据结构初始化失败!");
return;
}
inputType.value = 0;
// 显示选择框
showLayer.value = true;
};
1 month ago
// 监听websocket的消息
watchEffect(() => {
try {
if (!message.value) return; // 如果没有新消息,直接返回
const json = JSON.parse(message.value);
// console.info(json);
const evtType = json.type;
if (evtType != "Pong") {
emitter.emit("evtType", { type: evtType, data: message.value });
}
} finally {
}
});
1 month ago
// 显示断层图层数据的逻辑
const showFractureLayerData = () => {
if (!propertyParam.wellParamSettings.selectedOption) {
1 month ago
$toastMessage.warning("您还没有选择断裂分布图!", 2000);
1 month ago
return;
}
inputType.value = 1;
// 显示选择框
showLayer.value = true;
1 month ago
console.log("显示断层图层数据");
1 month ago
};
// 发送计算命令
const handleStartCalc = async () => {
try {
// 检查断裂分布图选择
let selectedChunk = null;
1 month ago
if (DeployAgainId.value > 0) {
1 month ago
// 是二次布井
selectedChunk = propertyParam.wellParamSettings.selectedOption;
} else {
let selectedValue = fractureFileData.value.find(
(chunk) => chunk.MapID === propertyParam.wellParamSettings.selectedOption
);
1 month ago
console.log("SelectedValue:", selectedValue, selectedValue.MapName);
1 month ago
selectedChunk = selectedValue?.MapName;
if (checkEmpty(selectedChunk)) {
1 month ago
$toastMessage.warning("您还没有选择断裂分布图!", 2000);
1 month ago
return;
}
}
if (!selectedChunk) {
1 month ago
$toastMessage.warning("您还没有选择断裂分布图!", 2000);
1 month ago
return;
}
if (!connectionId.value) {
1 month ago
$toastMessage.warning("实时消息连接未建立,请刷新页面重试!", 2000);
1 month ago
return;
}
// 检查必要参数
if (checkEmpty(propertyParam.wellParamSettings.boundaryLayer)) {
1 month ago
$toastMessage.warning("请选择边界图层!", 2000);
1 month ago
return;
}
if (checkEmpty(propertyParam.wellParamSettings.faultLayer)) {
1 month ago
$toastMessage.warning("请选择断层图层!", 2000);
1 month ago
return;
}
// 修改按钮状态
taskStarted.value = true;
// 组装计算参数
const smartWellParam = {
DeployAgainId: DeployAgainId.value,
1 month ago
clientId: localStorage.getItem("drawerToken"),
drawerId: localStorage.getItem("drawerToken"),
1 month ago
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,
1 month ago
SpeciaAngles: propertyParam.calcParamSettings.SpeciaAngles,
1 month ago
IgnoreMiniFault: propertyParam.calcParamSettings.IgnoreMiniFault,
MiniFaultLength:
parseInt(propertyParam.calcParamSettings.MiniFaultLength) || 1000,
},
};
const response = await startSmartWellCalc(smartWellParam);
1 month ago
console.log("调用 startSmartWellCalc 结果:", response);
1 month ago
if (!response) {
taskStarted.value = false;
taskId.value = "";
$toastMessage.error("智能布井失败: 服务器未返回任务ID");
return;
}
taskId.value = response;
1 month ago
progressVisible.value = true;
1 month ago
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,
})
);
}
1 month ago
const handleStopCalc = async () => {
1 month ago
// 停止计算的逻辑
1 month ago
console.log("停止计算");
1 month ago
try {
1 month ago
if (taskId.value && taskStarted) {
1 month ago
const response = await stopSmartWellCalc(taskId.value);
if (response) {
$toastMessage.info("成功停止计算任务");
// localStorage.removeItem("currentTaskId");
} else {
$toastMessage.warning("停止任务失败");
}
}
} catch (error) {
console.error("停止错误:", error);
} finally {
taskId.value = null;
// 更新本地存储
updateCalcInfo(0, "任务已停止", false);
1 month ago
progressVisible.value = false;
1 month ago
taskStarted.value = false;
emitMsg({
type: "calcRedraw",
data: JSON.stringify({ msg: '重新绘制' }),
});
}
};
const emitMsg = (data) => {
1 month ago
emitter.emit("evtType", data);
1 month ago
};
onMounted(async () => {
// 加载断裂图件
await getFractureFileList();
listenEmitter();
});
// 监听图层选择
const listenEmitter = () => {
1 month ago
emitter.on("selectedLayer", (data) => {
console.log("selectedLayer", data);
1 month ago
handleClose();
if (checkEmpty(data)) {
1 month ago
$toastMessage.warning("请选择图层!", 2000);
1 month ago
return;
}
switch (inputType.value) {
case 0:
propertyParam.wellParamSettings.boundaryLayer = data;
break;
case 1:
propertyParam.wellParamSettings.faultLayer = data;
break;
}
});
1 month ago
// 二次布井事件
emitter.on("reCalc", async (data) => {
console.log("二次布井:", 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("获取智能布井计算参数出错了");
}
});
1 month ago
// 计算参数
1 month ago
emitter.on("calcPropery", async (data) => {
console.log("计算参数:", data);
1 month ago
const response = await getWellRecommend(data.Id);
if (!response) {
$toastMessage.error("获取井推荐参数失败!");
return;
}
1 month ago
console.log("推荐参数:", response);
1 month ago
1 month ago
propertyParam.wellParamSettings.selectedOption = response.OutGraphicFile;
1 month ago
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;
1 month ago
// this.calcParamSettings.SpeciaAngles = response.AngleRangeValue; // 角度范围值
1 month ago
propertyParam.calcParamSettings.IgnoreMiniFault = data.IsSmallFracture;
propertyParam.calcParamSettings.MiniFaultLength = data.SmallFractureValue;
});
};
onBeforeUnmount(() => {
1 month ago
emitter.off("selectedLayer");
emitter.off("reCalc");
emitter.off("calcPropery");
handleStopCalc();
1 month ago
});
const handleClose = () => {
showLayer.value = false;
};
// 获取断裂图件
const getFractureFileList = async () => {
let response = await fractureFileList();
if (response) {
fractureFileData.value = response;
}
1 month ago
console.log("获取断裂图件结果:", response);
1 month ago
};
</script>
<style scoped>
.scrollable-form {
/* max-height: 900px; */
1 month ago
min-height: 600px;
1 month ago
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;
1 month ago
padding-bottom: 10px;
1 month ago
}
.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 {
1 month ago
height: 600px;
1 month ago
background: #ccc;
border: 1px solid #333;
}
.popup-tree {
1 month ago
height: 600px;
1 month ago
width: 100%;
}
</style>