Commit 4e25153b by zhaopanyu

zpy

parent e88bde77
......@@ -413,4 +413,63 @@ export default {
background-color: #e6e6e6;
border-color: #adadad;
}
/* 放大缩小按钮组样式 */
.toolbar-controls .el-button-group {
border: none;
background: transparent;
box-shadow: none;
}
.toolbar-controls .el-button-group .el-button {
width: 40px;
height: 40px;
padding: 0;
border: none;
border-radius: 10px;
background: linear-gradient(145deg, #f8f9fa 0%, #e9ecef 100%);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08),
inset 0 1px 0 rgba(255, 255, 255, 0.8);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
margin: 0 3px;
}
.toolbar-controls .el-button-group .el-button [class^="el-icon-"] {
font-size: 16px;
margin: 0;
transition: all 0.3s ease;
}
/* 放大按钮 - 蓝色系 */
.toolbar-controls .el-button-group .el-button .el-icon-zoom-in {
color: #409EFF;
}
.toolbar-controls .el-button-group .el-button:hover {
transform: translateY(-1px);
}
.toolbar-controls .el-button-group .el-button:hover .el-icon-zoom-in {
color: #fff;
transform: scale(1.1);
}
/* 缩小按钮 - 红色系 */
.toolbar-controls .el-button-group .el-button .el-icon-zoom-out {
color: #ff4757;
}
.toolbar-controls .el-button-group .el-button:hover .el-icon-zoom-out {
color: #fff;
transform: scale(1.1);
}
/* 通用悬停效果 */
.toolbar-controls .el-button-group .el-button:active {
transform: translateY(0);
box-shadow: 0 2px 6px rgba(64, 158, 255, 0.25);
}
</style>
\ No newline at end of file
<template>
<el-button
:icon="icon"
:plain="plain"
:loading="loading"
:title="title"
@click="handleClick"
>
<el-button :icon="icon" :plain="plain" :loading="loading" :title="title" @click="handleClick">
<slot></slot>
</el-button>
</template>
......@@ -40,4 +34,41 @@ export default {
</script>
<style scoped>
.el-button {
width: 40px;
height: 40px;
padding: 0;
border: none;
border-radius: 10px;
background: linear-gradient(145deg, #f8f9fa 0%, #e9ecef 100%);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08),
inset 0 1px 0 rgba(255, 255, 255, 0.8);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
}
.el-button [class^="el-icon-"] {
font-size: 16px;
margin: 0;
color: #28a745;
transition: all 0.3s ease;
}
.el-button:hover {
background: linear-gradient(145deg, #28a745 0%, #34ce57 100%);
box-shadow: 0 4px 12px rgba(40, 167, 69, 0.25),
0 2px 4px rgba(0, 0, 0, 0.1);
transform: translateY(-1px);
}
.el-button:hover [class^="el-icon-"] {
color: #fff;
transform: scale(1.1);
}
.el-button:active {
transform: translateY(0);
box-shadow: 0 2px 6px rgba(40, 167, 69, 0.25);
}
</style>
\ No newline at end of file
......@@ -26,7 +26,7 @@ export default {
height: { type: Number, default: 0 },
idOverride: { type: [String, Number], default: null }
},
data () {
data() {
return {
chart: null,
resizeObserver: null,
......@@ -46,7 +46,7 @@ export default {
points: []
}
},
mounted () {
mounted() {
// 仅使用延迟初始化,确保容器有尺寸后再 init
this.deferInit()
window.addEventListener('resize', this.resizeChart)
......@@ -69,16 +69,18 @@ export default {
})
}
},
created () {
created() {
// 尽早触发接口调用,进入页面即发起请求
this.loadDht()
},
activated () {
activated() {
// 当页面被 keep-alive 缓存后再次进入时,确保尺寸和图表刷新
this.deferInit()
this.resizeChart()
// 强制重新加载数据,确保路由参数变化时数据能更新
this.loadDht(true)
},
beforeDestroy () {
beforeDestroy() {
window.removeEventListener('resize', this.resizeChart)
if (this.chart) {
this.chart.dispose()
......@@ -89,9 +91,19 @@ export default {
this.resizeObserver = null
}
},
watch: {
// 监听idOverride变化,当路由参数变化时重新加载数据
idOverride(newId, oldId) {
if (newId !== oldId && newId) {
console.log('[ysgc] idOverride变化,重新加载数据:', newId);
this.dhtResult = null; // 清除缓存
this.loadDht(true);
}
}
},
methods: {
// 等待容器有有效尺寸再初始化,避免 echarts 容器宽高为 0 报错
deferInit () {
deferInit() {
const tryInit = () => {
const el = this.$refs.chartRef
if (!el) return
......@@ -135,10 +147,10 @@ export default {
}
this.$nextTick(tryInit)
},
resizeChart () {
resizeChart() {
if (this.chart) this.chart.resize()
},
initChart () {
initChart() {
const el = this.$refs.chartRef
if (!el) return
if (this.chart) {
......@@ -161,7 +173,7 @@ export default {
}
},
// 数据变化后自动刷新(确保缩略图及时绘制)
_requestRender () {
_requestRender() {
if (!this.chart) return
this.$nextTick(() => {
this.renderChart()
......@@ -174,8 +186,8 @@ export default {
})
},
// 调用地层/断层图接口(示例),优先从路由参数获取 id
loadDht () {
if (this.loadingDht || this.dhtResult) return
loadDht(forceReload = false) {
if (this.loadingDht || (this.dhtResult && !forceReload)) return
try {
const route = this.$route || {}
const params = route.params || {}
......@@ -202,7 +214,7 @@ export default {
}
},
// 将接口返回的数据应用到图表状态
applyDhtResult () {
applyDhtResult() {
const data = this.dhtResult || {}
// 边界
this.xMin = data.xmin != null ? Number(data.xmin) : this.xMin
......@@ -248,7 +260,7 @@ export default {
} catch (e) { }
},
// 生成图表配置
buildOption () {
buildOption() {
// 若未提供边界,则根据数据自动估算
const allXs = []
const allYs = []
......@@ -322,7 +334,7 @@ export default {
}
},
// 渲染或更新图表
renderChart () {
renderChart() {
if (!this.chart) return
const option = this.buildOption()
this.chart.setOption(option, true)
......@@ -330,7 +342,7 @@ export default {
this.bindChartEvents()
},
// 绑定点击/双击事件,把被点击的绿色线条映射为 segy 下标并上报
bindChartEvents () {
bindChartEvents() {
if (!this.chart) return
// 解除旧绑定避免重复
this.chart.off('click')
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
<template>
<div class="app-container">
<div class="app-containers">
<div class="containerBlock">
<div class="top-actions">
<div class="left-actions">
......@@ -7,36 +7,8 @@
<el-button size="small" @click="setHorizontalLayout">左右结构</el-button>
<el-button size="small" @click="handlePrevTrace">上一道</el-button>
<el-button size="small" @click="handleNextTrace">下一道</el-button>
<div ref="thumbContainer" @click="handleThumbClick" class="right-thumb">
<div class="thumb-title">缩略图</div>
<div ref="thumbHolder" class="thumb-holder">
<YsgcIndex v-if="thumbReady" :key="routeId + '-' + thumbReady" :compact="true" :width="260" :height="160"
:id-override="routeId" />
</div>
</div>
<!-- 缩略图弹窗 start -->
<el-dialog title="缩略图预览" :visible.sync="showThumbDialog" width="80%" append-to-body>
<div style="height: 100%;">
<YsgcIndex :id-override="routeId" @segyLinePick="onThumbLinePick" />
</div>
</el-dialog>
<!-- 缩略图弹窗 end -->
</div>
</div>
<!-- 添加加载状态和错误提示 -->
<div v-if="loadingError" class="error-message">
{{ loadingError }}
</div>
<div class="toolbar" v-if="isWidgetReady">
<!-- 左侧内容 -->
<div class="toolbar-left">
<!-- 左侧可以留空,或者将来添加其他控件 -->
</div>
<!-- 右侧按钮组 -->
<!-- 右侧按钮组(与左侧同一行,靠右对齐) -->
<div class="toolbar-right">
<div class="color-maps">
<el-select v-model="currentColorMap" @change="switchColorMap" size="small">
......@@ -62,14 +34,41 @@
<i class="el-icon-edit"></i>
</el-button>
</el-tooltip>
<el-tooltip :content="internalScrollbarSyncEnabled ? '内部滚动条同步已启用' : '内部滚动条同步已禁用'" placement="bottom"
<!-- <el-tooltip :content="internalScrollbarSyncEnabled ? '内部滚动条同步已启用' : '内部滚动条同步已禁用'" placement="bottom"
effect="light">
<el-button @click="toggleInternalScrollbarSync" :class="{ 'active': internalScrollbarSyncEnabled }">
<i class="el-icon-s-operation"></i>
</el-button>
</el-tooltip>
</el-tooltip> -->
</div>
<div v-if="shouldShowThumb" ref="thumbContainer" @click="handleThumbClick" class="right-thumb">
<div class="thumb-title">缩略图</div>
<div ref="thumbHolder" class="thumb-holder">
<YsgcIndex v-if="thumbReady" :key="'thumb-' + routeId + '-' + thumbReady" :compact="true" :width="260"
:height="160" :id-override="routeId" />
</div>
</div>
<!-- 缩略图弹窗 start -->
<el-dialog v-if="shouldShowThumb" title="缩略图预览" :visible.sync="showThumbDialog" width="80%" append-to-body>
<div style="height: 100%;">
<YsgcIndex :key="'dialog-thumb-' + routeId" :id-override="routeId" @segyLinePick="onThumbLinePick" />
</div>
</el-dialog>
<!-- 缩略图弹窗 end -->
</div>
<!-- 添加加载状态和错误提示 -->
<div v-if="loadingError" class="error-message">
{{ loadingError }}
</div>
<div class="toolbar" v-if="isWidgetReady">
<!-- 左侧内容 -->
<div class="toolbar-left">
<!-- 左侧可以留空,或者将来添加其他控件 -->
</div>
</div>
<div class="split-container" :class="layoutMode === 'vertical' ? 'layout-vertical' : 'layout-horizontal'">
<div class="sync-section" ref="topScroll" @scroll="onScroll('top')">
<div class="zoom-wrapper" ref="topWrapper"
......@@ -84,8 +83,6 @@
</div>
</div>
</div>
<!-- 添加鼠标悬停专用覆盖层 -->
<div ref="hoverLayer" class="hover-layer"></div>
<!-- 自定义右键菜单 -->
<div v-if="contextMenu.visible" class="context-menu" :style="{
left: `${contextMenu.x}px`,
......@@ -342,7 +339,7 @@ export default {
LineStylePanel,
YsgcIndex
},
data () {
data() {
return {
// 布局模式:vertical 上下结构;horizontal 左右结构
layoutMode: 'vertical',
......@@ -700,11 +697,11 @@ export default {
thumbReady: false,
showThumbDialog: false, // 缩略图大图弹窗可见性
// 是否允许在未指定项目/无接口数据时加载示例数据
shouldLoadDemo: false,
shouldLoadDemo: true,
};
},
computed: {
routeId () {
routeId() {
try {
const route = this.$route || {};
const params = route.params || {};
......@@ -713,9 +710,39 @@ export default {
} catch (e) {
return this.thumbId || null;
}
},
shouldShowThumb() {
// 只在当前页面显示缩略图,通过路由路径判断
try {
const route = this.$route || {};
const path = route.path || '';
// 如果路径包含 'ysgc' 或者 'index2',则显示缩略图
return path.includes('ysgc') || path.includes('index2');
} catch (e) {
return false;
}
}
},
watch: {
// 监听路由变化,当路由参数改变时重新初始化数据
'$route'(to, from) {
console.log('[index2] 路由变化:', to.query, from.query);
// 如果路由参数发生变化,重新初始化组件
if (to.query.id !== from.query.id || to.query.zbid !== from.query.zbid) {
this.handleRouteChange();
}
},
// 监听routeId变化
routeId(newId, oldId) {
console.log('[index2] routeId变化:', newId, oldId);
if (newId !== oldId) {
this.handleRouteChange();
// 强制刷新缩略图
this.forceRefreshThumb();
}
}
},
mounted () {
mounted() {
// 初始化时强制设置为初始状态
this.resetToInitialState();
......@@ -757,14 +784,21 @@ export default {
// 无接口数据:若没有路由id,允许加载演示数据;若有id但无数据,保持空白
const hasId = !!this.routeId;
if (!hasId) {
this.shouldLoadDemo = false;
this.shouldLoadDemo = true;
try { await this.handleFileSelect(this.plots); } catch (e) { }
} else {
this.clearCurrentPlots();
this.$message.info('该项目无可用SEGY数据');
console.info('[index2] 该项目无可用SEGY数据');
}
}
} catch (e) {
console.warn('[index2] 自动加载数据失败:', e);
// 加载失败时,如果没有路由ID,尝试加载演示数据
if (!this.routeId) {
this.shouldLoadDemo = true;
try { await this.handleFileSelect(this.plots); } catch (e) { }
}
}
} catch (e) { /* ignore */ }
});
if (this.$refs.plot) {
......@@ -774,8 +808,26 @@ export default {
// 添加键盘事件监听
}
},
// 删除重复的 mounted,避免生命周期被覆盖
beforeDestroy () {
mounted() {
// 将缩略图容器移动到body,确保fixed基于视口
if (this.$refs.thumbContainer && this.$refs.thumbContainer.parentNode !== document.body) {
document.body.appendChild(this.$refs.thumbContainer);
}
this.createScene(this.$refs.plot);
// 等DOM稳定后再渲染缩略图组件
setTimeout(() => {
this.thumbReady = true;
// 再兜底:确保右上角出现内容,并直接绘制缩略图
setTimeout(() => {
this.ensureThumbRendered();
}, 200);
}, 100);
console.log('测试函数已添加:');
console.log('- window.testOuterScrollbarSync() - 测试外层滚动条同步');
console.log('- window.testInternalScrollbarHidden() - 测试内部滚动条隐藏');
},
beforeDestroy() {
// 移除右键菜单事件监听
if (this.$refs.plot) {
this.$refs.plot.removeEventListener('contextmenu', this.showContextMenu);
......@@ -787,7 +839,73 @@ export default {
window.removeEventListener('resize', this.updateBaseCanvasSize);
},
methods: {
ensureThumbRendered () {
// 处理路由变化的方法
async handleRouteChange() {
console.log('[index2] 处理路由变化,重新初始化组件');
// 重置组件状态
this.resetToInitialState();
// 清空当前图表
this.clearCurrentPlots();
// 重置缩略图状态
this.thumbReady = false;
this.segyList = [];
this.currentSegyIndex = 0;
// 等待DOM更新
await this.$nextTick();
// 重新初始化场景
if (this.$refs.plot) {
this.createScene(this.$refs.plot, { autoloadDemo: false });
}
// 重新加载数据
try {
await this.loadThumbData();
if (Array.isArray(this.segyList) && this.segyList.length > 0) {
await this.loadCurrentSegy();
} else {
// 无接口数据:若没有路由id,允许加载演示数据;若有id但无数据,保持空白
const hasId = !!this.routeId;
if (!hasId) {
this.shouldLoadDemo = false;
try {
await this.handleFileSelect(this.plots);
} catch (e) {
console.warn('[index2] 加载演示数据失败:', e);
}
} else {
this.clearCurrentPlots();
console.info('[index2] 该项目无可用SEGY数据');
}
}
} catch (e) {
console.error('[index2] 重新加载数据失败:', e);
this.loadingError = '数据加载失败,请刷新页面重试';
}
// 重新初始化缩略图 - 让YsgcIndex组件自己处理数据加载
this.thumbReady = false;
setTimeout(() => {
this.thumbReady = true;
// YsgcIndex组件会通过idOverride属性自动加载数据,不需要手动处理
}, 100);
},
// 强制刷新缩略图
forceRefreshThumb() {
console.log('[index2] 强制刷新缩略图');
this.thumbReady = false;
this.$nextTick(() => {
this.thumbReady = true;
// YsgcIndex组件会通过key值变化自动重新渲染并加载数据
});
},
ensureThumbRendered() {
try {
const holder = this.$refs.thumbHolder;
if (!holder) return;
......@@ -806,7 +924,7 @@ export default {
}
} catch (e) { /* ignore */ }
},
drawThumbDirect () {
drawThumbDirect() {
try {
const holder = this.$refs.thumbHolder;
if (!holder) return;
......@@ -851,7 +969,6 @@ export default {
if (seg) {
// 加载该线对应的新/旧SEGY:jbsegy -> 顶部,xbsegy -> 底部
this.loadDualSegyFiles(seg.jbsegy, seg.xbsegy, seg.jbsegyName, seg.xbsegyName);
this.$message.success(`已加载第${lineIdx + 1}条线的数据`);
}
}
}
......@@ -860,23 +977,23 @@ export default {
} catch (e) { /* ignore */ }
},
// 顶部操作:切换布局与上一/下一道(占位)
setVerticalLayout () {
setVerticalLayout() {
this.layoutMode = 'vertical';
this.showDualChart();
this.$nextTick(() => this.resizeAfterLayout());
},
// 已移除全局浮动缩略图容器,缩略图仅在本页右上角显示
setHorizontalLayout () {
setHorizontalLayout() {
this.layoutMode = 'horizontal';
this.showDualChart();
this.$nextTick(() => this.resizeAfterLayout());
},
resizeAfterLayout () {
resizeAfterLayout() {
try { this.updateBaseCanvasSize(); } catch (e) { }
try { this._seismicWidget && this._seismicWidget.invalidate(); } catch (e) { }
try { this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate(); } catch (e) { }
},
async handlePrevTrace () {
async handlePrevTrace() {
console.log('[index2] 上一道 clicked');
if (!Array.isArray(this.segyList) || this.segyList.length === 0) {
console.log('[index2] segyList 为空,尝试重新加载');
......@@ -885,7 +1002,7 @@ export default {
} catch (e) { console.warn('[index2] 重新加载segy失败:', e); }
}
if (!Array.isArray(this.segyList) || this.segyList.length === 0) {
this.$message.warning('没有可用的segy数据');
console.warn('[index2] 没有可用的segy数据');
return;
}
......@@ -896,7 +1013,7 @@ export default {
// 加载当前segy文件
this.loadCurrentSegy();
},
async handleNextTrace () {
async handleNextTrace() {
console.log('[index2] 下一道 clicked');
if (!Array.isArray(this.segyList) || this.segyList.length === 0) {
console.log('[index2] segyList 为空,尝试重新加载');
......@@ -905,7 +1022,7 @@ export default {
} catch (e) { console.warn('[index2] 重新加载segy失败:', e); }
}
if (!Array.isArray(this.segyList) || this.segyList.length === 0) {
this.$message.warning('没有可用的segy数据');
console.warn('[index2] 没有可用的segy数据');
return;
}
......@@ -917,7 +1034,7 @@ export default {
this.loadCurrentSegy();
},
// 加载当前segy文件
async loadCurrentSegy () {
async loadCurrentSegy() {
if (this.segyList.length === 0) {
console.log('[index2] 没有segy数据可加载');
return;
......@@ -938,11 +1055,10 @@ export default {
} catch (error) {
console.error('[index2] 加载segy文件失败:', error);
this.$message.error('加载segy文件失败');
}
},
// 清空当前图表
clearCurrentPlots () {
clearCurrentPlots() {
console.log('[index2] 清空当前图表');
try {
// 清空主图表
......@@ -961,7 +1077,7 @@ export default {
}
},
// 加载segy文件的具体实现
async loadSegyFile (segyPath) {
async loadSegyFile(segyPath) {
console.log('[index2] 开始加载segy文件:', segyPath);
try {
......@@ -984,10 +1100,10 @@ export default {
}
},
// 同时加载上下两个segy(jbsegy到顶部,xbsegy到底部)
async loadDualSegyFiles (jbPath, xbPath, jbName, xbName) {
async loadDualSegyFiles(jbPath, xbPath, jbName, xbName) {
// 兜底:若无路径,则给出提示
if (!jbPath && !xbPath) {
this.$message.warning('无可加载的SEGY文件');
console.warn('[index2] 无可加载的SEGY文件');
return;
}
......@@ -1006,38 +1122,40 @@ export default {
let bottomOk = false;
try {
if (jbPath) {
await this.loadSegyIntoWidget('top', jbPath, jbName || 'jbsegy');
const topTitle = jbName || this.extractFileName(jbPath) || 'jbsegy';
await this.loadSegyIntoWidget('top', jbPath, topTitle);
topOk = true;
}
} catch (e) {
console.warn('加载上部SEGY失败:', e);
this.$message.error(`上部SEGY加载失败${jbName ? ':' + jbName : ''}`);
}
try {
if (xbPath) {
await this.loadSegyIntoWidget('bottom', xbPath, xbName || 'xbsegy');
const bottomTitle = xbName || this.extractFileName(xbPath) || 'xbsegy';
await this.loadSegyIntoWidget('bottom', xbPath, bottomTitle);
bottomOk = true;
}
} catch (e) {
console.warn('加载下部SEGY失败:', e);
this.$message.error(`下部SEGY加载失败${xbName ? ':' + xbName : ''}`);
}
if (topOk && bottomOk) {
this.$message.success('上/下部SEGY加载完成');
console.info('[index2] 上/下部SEGY加载完成');
} else if (topOk || bottomOk) {
this.$message.warning(`${topOk ? '上部' : '下部'}SEGY加载成功,另一个失败`);
console.warn('[index2] 一侧SEGY加载成功,另一侧失败');
}
},
// 将指定segy加载到顶部/底部widget
async loadSegyIntoWidget (position, segyPath, displayName) {
async loadSegyIntoWidget(position, segyPath, displayName) {
// 构造可访问的完整URL
const url = this.buildSegyURL(segyPath);
// 拉取二进制
console.log('[index2] 即将拉取SEGY', { position, name: displayName, rawPath: segyPath, builtUrl: url });
const blob = await this.fetchSegyBlob(url);
const fileName = (displayName || segyPath || '').split('/').pop() || 'data.segy';
console.log('[index2] 已获取SEGY二进制', { position, name: displayName, size: blob && blob.size, type: blob && blob.type });
const fileName = (displayName || this.extractFileName(segyPath) || 'data.segy');
const filesObj = new File([blob], fileName, { type: blob.type || 'application/octet-stream', lastModified: Date.now() });
const file = new LocalFile(filesObj);
......@@ -1081,7 +1199,7 @@ export default {
if (!this._seismicWidget && this.$refs.plot) this.createScene(this.$refs.plot);
if (!this._seismicWidget) throw new Error('顶部Widget未初始化');
this._seismicWidget.setPipeline(pipeline);
this._seismicWidget.setOptions({ 'axes': { 'samples': { 'title': { 'visible': true, 'text': displayName || pipeline.getName() } } } });
this._seismicWidget.setOptions({ 'axes': { 'samples': { 'title': { 'visible': true, 'text': displayName || this.extractFileName(segyPath) || pipeline.getName() } } } });
setTimeout(() => { try { this._seismicWidget.fitToBounds(); } catch (e) { } }, 200);
this.setScrollbarCSS(this._seismicWidget);
this.forceDisableInternalScrollbars();
......@@ -1090,14 +1208,14 @@ export default {
if (!this._seismicWidgetBottom && this.$refs.plot2) this.initSecondWidget(this.$refs.plot2);
if (!this._seismicWidgetBottom) throw new Error('底部Widget未初始化');
this._seismicWidgetBottom.setPipeline(pipeline);
this._seismicWidgetBottom.setOptions({ 'axes': { 'samples': { 'title': { 'visible': true, 'text': displayName || pipeline.getName() } } } });
this._seismicWidgetBottom.setOptions({ 'axes': { 'samples': { 'title': { 'visible': true, 'text': displayName || this.extractFileName(segyPath) || pipeline.getName() } } } });
setTimeout(() => { try { this._seismicWidgetBottom.fitToBounds(); } catch (e) { } }, 200);
this.setScrollbarCSS(this._seismicWidgetBottom);
this.forceDisableInternalScrollbars();
}
},
// 根据后端网关构造SEGY访问URL
buildSegyURL (path) {
buildSegyURL(path) {
if (!path) return '';
// 如果已经是完整URL,直接返回
if (/^https?:\/\//i.test(path)) return path;
......@@ -1110,17 +1228,76 @@ export default {
}
return `${base}${p}`;
},
// 提取路径中的文件名
extractFileName(p) {
try {
if (!p) return '';
const clean = String(p).split('?')[0];
return clean.split('/').pop() || '';
} catch (e) { return ''; }
},
// 拉取SEGY二进制
async fetchSegyBlob (url) {
async fetchSegyBlob(url) {
if (!url) throw new Error('无效的SEGY地址');
const res = await fetch(url, { headers: { Authorization: 'Bearer ' + getToken() } });
if (!res.ok) throw new Error(`网络请求失败: ${res.status} ${res.statusText}`);
const token = getToken();
const base = (process.env.VUE_APP_BASE_API || '').replace(/\/$/, '');
const headers = { Authorization: 'Bearer ' + token };
// 构造候选URL列表:优先使用传入的url,然后尝试直接资源路径等
const attempts = [];
attempts.push({ url, headers });
const dlMatch = url.match(/\/(common\/download\/resource)\?resource=([^&]+)/);
if (dlMatch) {
const resourceEnc = dlMatch[2];
const resource = decodeURIComponent(resourceEnc);
// 直接用 base + resource
if (base && resource) attempts.push({ url: `${base}${resource}`, headers });
// 仅用资源相对路径
if (resource) attempts.push({ url: resource, headers });
}
// 同一批URL再尝试无鉴权头(有些静态资源是公开的)
const more = attempts.map(a => ({ url: a.url }));
attempts.push(...more);
// 针对编码resource的404,再试未编码版本
const encodedMatch = url.match(/resource=([^&]+)/);
if (encodedMatch) {
const rawUrl = url.replace(/resource=([^&]+)/, (m, v) => `resource=${decodeURIComponent(v)}`);
attempts.unshift({ url: rawUrl, headers });
attempts.push({ url: rawUrl });
}
const errors = [];
for (const attempt of attempts) {
try {
console.log('[index2] fetchSegyBlob 尝试', { url: attempt.url, withAuth: !!attempt.headers });
const res = await fetch(attempt.url, attempt.headers ? { headers: attempt.headers } : {});
if (!res.ok) {
const text = await res.text().catch(() => '');
errors.push(`${attempt.url} -> ${res.status} ${res.statusText}${text ? ' - ' + text.slice(0, 120) : ''}`);
continue;
}
const contentType = (res.headers && res.headers.get && res.headers.get('content-type')) || '';
const blob = await res.blob();
if (!blob || blob.size === 0) throw new Error('获取到的文件数据为空');
return blob;
// 拦截返回HTML或可疑体积的情况,避免GeoToolkit解析报错
if (/(text\/html|application\/json)/i.test(contentType)) {
const text = await res.text().catch(() => '');
errors.push(`${attempt.url} -> 非SEGY(HTML/JSON),内容: ${text.slice(0, 120)}`);
continue;
}
if (blob && blob.size > 0) return blob;
errors.push(`${attempt.url} -> 空文件(size=0)`);
} catch (e) {
errors.push(`${attempt.url} -> 异常: ${e && e.message ? e.message : e}`);
}
}
throw new Error('获取到的文件数据为空;尝试的URL:\n' + errors.join('\n'));
},
// 显示单个图表(隐藏底部图表)
showSingleChart () {
showSingleChart() {
console.log('[index2] 切换到单图表显示模式');
// 隐藏底部图表容器
......@@ -1140,7 +1317,7 @@ export default {
this.layoutMode = 'single';
},
// 显示双图表(恢复上下或左右布局)
showDualChart () {
showDualChart() {
console.log('[index2] 切换到双图表显示模式');
// 显示底部图表容器
......@@ -1162,7 +1339,7 @@ export default {
}
},
// 清空场景
clearScene (container) {
clearScene(container) {
if (!container) return;
try {
......@@ -1178,11 +1355,11 @@ export default {
console.warn('[index2] 清空场景时出错:', e);
}
},
handleThumbClick () {
handleThumbClick() {
this.showThumbDialog = true;
},
// 处理缩略图(绿色线)点击/双击事件
onThumbLinePick (payload) {
onThumbLinePick(payload) {
try {
if (!payload || typeof payload.index !== 'number') return;
const lineIdx = payload.index;
......@@ -1191,24 +1368,23 @@ export default {
this.currentSegyIndex = lineIdx;
if (seg) {
this.loadDualSegyFiles(seg.jbsegy, seg.xbsegy, seg.jbsegyName, seg.xbsegyName);
this.$message.success(`已加载第${lineIdx + 1}条线的数据`);
}
} catch (e) { /* ignore */ }
},
// 确保缩略图渲染
ensureThumbRendered () {
ensureThumbRendered() {
if (!this.thumbReady) {
this.thumbReady = true;
}
},
// ====== 缩略图(ECharts) ======
async initThumb () {
async initThumb() {
// 已弃用:现在缩略图直接嵌入 YsgcIndex
return;
},
// 测试缩略图方法
testThumb () {
testThumb() {
console.log('[index2] ===== testThumb START =====');
// 创建完全独立的测试容器
......@@ -1243,7 +1419,7 @@ export default {
console.log('[index2] ===== testThumb END =====');
},
// 测试ECharts方法
testECharts () {
testECharts() {
console.log('[index2] ===== testECharts START =====');
// 清理现有容器
......@@ -1326,14 +1502,14 @@ export default {
console.log('[index2] ===== testECharts END =====');
},
// 测试按钮点击
testButtonClick () {
testButtonClick() {
console.log('[index2] ===== testButtonClick START =====');
alert('按钮点击测试成功!');
console.log('[index2] ===== testButtonClick END =====');
},
// 创建超级明显的缩略图测试
createSuperVisibleThumb () {
createSuperVisibleThumb() {
console.log('[index2] ===== createSuperVisibleThumb START =====');
// 清理现有容器
......@@ -1480,7 +1656,7 @@ export default {
console.log('[index2] ===== createSuperVisibleThumb END =====');
},
// 重置缩略图方法
resetThumb () {
resetThumb() {
console.log('[index2] ===== resetThumb START =====');
// 清理独立容器
......@@ -1525,7 +1701,7 @@ export default {
console.log('[index2] ===== resetThumb END =====');
},
// 备用缩略图初始化方法
async initThumbFallback () {
async initThumbFallback() {
console.log('[index2] ===== initThumbFallback START =====');
try {
// 创建完全独立的ECharts容器
......@@ -1639,7 +1815,7 @@ export default {
}
console.log('[index2] ===== initThumbFallback END =====');
},
async loadThumbData () {
async loadThumbData() {
try {
// 与 index.vue 相同的取数方式:优先从路由取 id
const route = this.$route || {};
......@@ -1737,7 +1913,7 @@ export default {
console.warn('[index2] loadThumbData failed:', e);
}
},
buildThumbOption () {
buildThumbOption() {
const series = [];
if (this.thumbPoints && this.thumbPoints.length) {
series.push({
......@@ -1840,7 +2016,7 @@ export default {
}]
};
},
renderThumb () {
renderThumb() {
if (!this.thumbChart) {
console.warn('[index2] renderThumb: no chart instance');
return;
......@@ -1864,7 +2040,7 @@ export default {
}
},
// 更新基准宽高,基于外层容器实际尺寸
updateBaseCanvasSize () {
updateBaseCanvasSize() {
try {
const topEl = this.$refs.topScroll;
if (topEl) {
......@@ -1884,7 +2060,7 @@ export default {
},
// 根据 GeoToolkit 模型范围动态计算滚动区域尺寸
updateScrollAreaSize () {
updateScrollAreaSize() {
try {
if (!this._seismicWidget) return;
......@@ -1958,7 +2134,7 @@ export default {
},
// 彻底禁用滚动条工具
disableScrollbarTools () {
disableScrollbarTools() {
try {
// 等待widget创建完成后再禁用
setTimeout(() => {
......@@ -1975,7 +2151,7 @@ export default {
},
// 禁用单个widget的滚动条
disableWidgetScrollbar (widget) {
disableWidgetScrollbar(widget) {
try {
if (!widget) return;
......@@ -2058,7 +2234,7 @@ export default {
},
// 强制隐藏滚动条DOM元素
forceHideScrollbarDOM (widget) {
forceHideScrollbarDOM(widget) {
try {
if (!widget || !widget.getCanvas) return;
......@@ -2129,7 +2305,7 @@ export default {
},
// 强制重置到初始状态,不显示滚动条
resetToInitialState () {
resetToInitialState() {
try {
const topEl = this.$refs.topScroll;
if (topEl) {
......@@ -2149,7 +2325,7 @@ export default {
},
// 创建下半屏镜像视图
initSecondWidget (canvas) {
initSecondWidget(canvas) {
try {
this.plotsBottom = new Plot({
'canvasElement': canvas,
......@@ -2223,7 +2399,7 @@ export default {
},
// 同步滚动条(左右与上下)- 防死循环版本
onScroll (origin) {
onScroll(origin) {
// 多重防护:防止死循环
if (this._isSyncingScroll || this._scrollSyncTimeout) return;
......@@ -2263,7 +2439,7 @@ export default {
},
// 让顶部/底部视图缩放同步
ensureZoomSyncHook () {
ensureZoomSyncHook() {
if (this._zoomHooked) return;
const top = this._seismicWidget;
const bottom = this._seismicWidgetBottom;
......@@ -2323,7 +2499,7 @@ export default {
},
// 更新内部滚动条工具
updateWidgetScrollbar (widget) {
updateWidgetScrollbar(widget) {
try {
const toolManager = widget && widget.getTool && widget.getTool();
if (!toolManager || !toolManager.getScrollbarTool) return;
......@@ -2335,7 +2511,7 @@ export default {
},
// 强制禁用内部滚动条
forceDisableInternalScrollbars (widget) {
forceDisableInternalScrollbars(widget) {
if (!widget) return;
try {
......@@ -2408,7 +2584,7 @@ export default {
},
// 定期检查并禁用内部滚动条
startScrollbarMonitor () {
startScrollbarMonitor() {
if (this._scrollbarMonitorInterval) {
clearInterval(this._scrollbarMonitorInterval);
}
......@@ -2451,7 +2627,7 @@ export default {
},
// 停止滚动条监控
stopScrollbarMonitor () {
stopScrollbarMonitor() {
if (this._scrollbarMonitorInterval) {
clearInterval(this._scrollbarMonitorInterval);
this._scrollbarMonitorInterval = null;
......@@ -2459,7 +2635,7 @@ export default {
},
// 使用CSS方法彻底禁用内部滚动条
setScrollbarCSS (widget) {
setScrollbarCSS(widget) {
if (!widget || !widget.setCss) return;
try {
......@@ -2569,7 +2745,7 @@ export default {
},
// 强制同步内部滚动条(如果必须保留内部滚动条)
enableInternalScrollbarSync () {
enableInternalScrollbarSync() {
if (!this._seismicWidget || !this._seismicWidgetBottom) return;
try {
......@@ -2588,7 +2764,7 @@ export default {
},
// 设置外层滚动条同步(GeoToolkit 3.2.80兼容模式)
setupOuterScrollbarSync () {
setupOuterScrollbarSync() {
if (!this._seismicWidget || !this._seismicWidgetBottom) return;
try {
// 清除之前的监听器
......@@ -2660,7 +2836,7 @@ export default {
},
// 清除外层滚动条监听器
clearOuterScrollbarListeners () {
clearOuterScrollbarListeners() {
try {
if (this._outerScrollListeners) {
this._outerScrollListeners.forEach(({ element, event, handler }) => {
......@@ -2676,9 +2852,9 @@ export default {
},
// 防抖函数
debounce (func, wait) {
debounce(func, wait) {
let timeout;
return function executedFunction (...args) {
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
......@@ -2689,7 +2865,7 @@ export default {
},
// 设置DOM级别的滚动条同步
setupDOMScrollbarSync () {
setupDOMScrollbarSync() {
try {
// 清除之前的DOM监听器
this.clearDOMScrollbarListeners();
......@@ -2760,7 +2936,7 @@ export default {
},
// 获取外层滚动容器(GeoToolkit 3.2.80兼容)
getOuterScrollContainer (widget) {
getOuterScrollContainer(widget) {
try {
if (!widget || !widget.getCanvas) return null;
......@@ -2796,7 +2972,7 @@ export default {
},
// 同步GeoToolkit内部视图(GeoToolkit 3.2.80兼容)
syncGeoToolkitView (widget, scrollLeft, scrollTop) {
syncGeoToolkitView(widget, scrollLeft, scrollTop) {
try {
if (!widget) return;
......@@ -2856,7 +3032,7 @@ export default {
},
// 启动外层滚动条同步监控(GeoToolkit 3.2.80兼容)
startOuterScrollbarSyncMonitor () {
startOuterScrollbarSyncMonitor() {
if (this._outerScrollbarSyncInterval) {
clearInterval(this._outerScrollbarSyncInterval);
}
......@@ -2871,7 +3047,7 @@ export default {
},
// 强制外层滚动条同步(GeoToolkit 3.2.80兼容)
forceOuterScrollbarSync () {
forceOuterScrollbarSync() {
try {
if (!this._seismicWidget || !this._seismicWidgetBottom) return;
......@@ -2915,7 +3091,7 @@ export default {
},
// 停止外层滚动条同步监控
stopOuterScrollbarSyncMonitor () {
stopOuterScrollbarSyncMonitor() {
if (this._outerScrollbarSyncInterval) {
clearInterval(this._outerScrollbarSyncInterval);
this._outerScrollbarSyncInterval = null;
......@@ -2923,7 +3099,7 @@ export default {
},
// 强制隐藏所有内部滚动条
forceHideAllInternalScrollbars () {
forceHideAllInternalScrollbars() {
try {
// 方法1: 禁用widget滚动条
if (this._seismicWidget) {
......@@ -2949,7 +3125,7 @@ export default {
},
// 启动强力滚动条隐藏监控
startAggressiveScrollbarHideMonitor () {
startAggressiveScrollbarHideMonitor() {
if (this._scrollbarHideInterval) {
clearInterval(this._scrollbarHideInterval);
}
......@@ -2970,7 +3146,7 @@ export default {
},
// 禁用滚动条交互
disableScrollbarInteractions () {
disableScrollbarInteractions() {
try {
const rootEl = this.$el || document;
const scrollbarElements = rootEl.querySelectorAll ? rootEl.querySelectorAll('.sync-section [class*="scrollbar"], .sync-section [class*="Scrollbar"], .sync-section [class*="scroll"], .sync-section [class*="Scroll"], .sync-section [class*="geotoolkit.controls.tools.scroll"]') : [];
......@@ -3010,7 +3186,7 @@ export default {
},
// 停止滚动条隐藏监控
stopScrollbarHideMonitor () {
stopScrollbarHideMonitor() {
if (this._scrollbarHideInterval) {
clearInterval(this._scrollbarHideInterval);
this._scrollbarHideInterval = null;
......@@ -3018,7 +3194,7 @@ export default {
},
// 测试外层滚动条同步(GeoToolkit 3.2.80兼容)
testOuterScrollbarSync () {
testOuterScrollbarSync() {
try {
console.log('=== 测试外层滚动条同步 ===');
......@@ -3064,7 +3240,7 @@ export default {
},
// 测试内部滚动条是否被隐藏
testInternalScrollbarHidden () {
testInternalScrollbarHidden() {
try {
console.log('=== 测试内部滚动条是否被隐藏 ===');
......@@ -3118,7 +3294,7 @@ export default {
},
// 强制禁用内部滚动条(GeoToolkit 3.2.80兼容)
forceDisableInternalScrollbars () {
forceDisableInternalScrollbars() {
try {
if (!this._seismicWidget || !this._seismicWidgetBottom) return;
......@@ -3172,18 +3348,18 @@ export default {
},
// 启动滚动条同步状态监控
startScrollbarSyncStatusMonitor () {
startScrollbarSyncStatusMonitor() {
// 已禁用内部滚动条同步,直接返回
return;
},
// 确保滚动条同步(已禁用内部同步,直接返回)
ensureScrollbarSync () {
ensureScrollbarSync() {
return;
},
// 停止滚动条同步状态监控
stopScrollbarSyncStatusMonitor () {
stopScrollbarSyncStatusMonitor() {
if (this._scrollbarSyncStatusInterval) {
clearInterval(this._scrollbarSyncStatusInterval);
this._scrollbarSyncStatusInterval = null;
......@@ -3191,14 +3367,14 @@ export default {
},
// 添加强制隐藏滚动条的CSS(GeoToolkit 3.2.80兼容)
addForceHideScrollbarCSS () {
addForceHideScrollbarCSS() {
// 为避免影响全局左侧菜单,这里不再注入全局隐藏滚动条的样式。
// 内部滚动条隐藏交由 .sync-section 作用域 CSS 与 DOM 级隐藏来完成。
return;
},
// 启动强力滚动条监控
startAggressiveScrollbarMonitor () {
startAggressiveScrollbarMonitor() {
// 仅监控本页面容器,避免影响全局(菜单/标题)
if (this._scrollbarObserver) {
this._scrollbarObserver.disconnect();
......@@ -3236,7 +3412,7 @@ export default {
},
// 隐藏单个滚动条元素
hideScrollbarElement (element) {
hideScrollbarElement(element) {
if (!element || !element.classList) return;
const classList = Array.from(element.classList);
......@@ -3260,7 +3436,7 @@ export default {
},
// 强制隐藏所有滚动条(仅作用于给定根节点,默认当前组件内)
forceHideAllScrollbars (root) {
forceHideAllScrollbars(root) {
const rootEl = root || this.$el || document;
const query = rootEl.querySelectorAll ? rootEl.querySelectorAll.bind(rootEl) : document.querySelectorAll.bind(document);
const selectors = [
......@@ -3283,7 +3459,7 @@ export default {
},
// 停止强力滚动条监控
stopAggressiveScrollbarMonitor () {
stopAggressiveScrollbarMonitor() {
if (this._scrollbarObserver) {
this._scrollbarObserver.disconnect();
this._scrollbarObserver = null;
......@@ -3295,7 +3471,7 @@ export default {
},
// 强制禁用所有滚动条
forceDisableAllScrollbars () {
forceDisableAllScrollbars() {
try {
// 禁用widget滚动条
if (this._seismicWidget) {
......@@ -3318,7 +3494,7 @@ export default {
},
// 添加全局滚动条隐藏CSS
addGlobalScrollbarHideCSS () {
addGlobalScrollbarHideCSS() {
try {
// 检查是否已经添加过样式
if (document.getElementById('geotoolkit-scrollbar-hide')) {
......@@ -3359,7 +3535,7 @@ export default {
}
},
createScene (canvas, options) {
createScene(canvas, options) {
try {
const autoFormat = new AutoNumberFormat(4);
// 创建 Plot 实例,同时创建 SeismicWidget
......@@ -3545,7 +3721,7 @@ export default {
}
},
handleFileSelect (plot) {
handleFileSelect(plot) {
let url = process.env.VUE_APP_BASE_API + "/ndy/dz/getSegyDataFile?fileName=density.segy";
let fileName = 'density.segy';
......@@ -3710,20 +3886,20 @@ export default {
});
},
handleMouseMove (event) {
handleMouseMove(event) {
if (!this._seismicWidget || !this.isHovering) return;
// 使用内置状态栏,不需要额外的处理逻辑
},
onFileOpen (evt, plot, fileInfo) {
onFileOpen(evt, plot, fileInfo) {
evt.stopPropagation();
evt.preventDefault();
const files = evt.target.files;
return this.handleFileSelect(this.plots);
},
initAnnotationTools (widget) {
initAnnotationTools(widget) {
if (!this.checkWidgetStatus()) {
console.error('Widget status check failed');
return;
......@@ -3862,7 +4038,7 @@ export default {
}
},
toggleDrawText () {
toggleDrawText() {
if (!this.checkWidgetStatus() || !this.isWidgetReady) {
console.warn('Widget or annotation tools not ready');
return;
......@@ -4026,7 +4202,7 @@ export default {
}
},
removeAnnotation () {
removeAnnotation() {
if (this.annotationTool && this.annotationTool.isEnabled() &&
this.annotationTool.getMode() === PaintMode.Edit &&
this.annotationTool.getShape()) {
......@@ -4039,7 +4215,7 @@ export default {
}
},
updateAllStyles () {
updateAllStyles() {
if (this.annotationTool && this.annotationTool.getShape()) {
const shape = this.annotationTool.getShape();
......@@ -4122,7 +4298,7 @@ export default {
},
// 修改字体大小变化处理方法
handleFontSizeChange (value) {
handleFontSizeChange(value) {
this.textStyle.size = value;
this.updateAllStyles();
......@@ -4162,7 +4338,7 @@ export default {
},
// 修改字体变化处理方法
handleFontChange (value) {
handleFontChange(value) {
this.textStyle.font = value;
this.updateAllStyles();
......@@ -4201,15 +4377,15 @@ export default {
},
// 修改字体样式处理方法
handleFontStyleChange () {
handleFontStyleChange() {
this.updateAllStyles();
},
updateTextStyle () {
updateTextStyle() {
this.updateAllStyles();
},
updateLineStyle () {
updateLineStyle() {
// 创建新的线条样式
const lineStyle = new LineStyle({
color: this.lineStyle.color,
......@@ -4273,11 +4449,11 @@ export default {
}
},
updateFillStyle () {
updateFillStyle() {
this.updateAllStyles();
},
getFillPatternStyle (key) {
getFillPatternStyle(key) {
// 基本样式对象
const baseStyle = {
height: '24px',
......@@ -4318,7 +4494,7 @@ export default {
return baseStyle;
},
getLinePatternStyle (key) {
getLinePatternStyle(key) {
let dashStyle = '';
// 使用处理后的线条模式
......@@ -4339,7 +4515,7 @@ export default {
};
},
getProcessedLinePattern (pattern) {
getProcessedLinePattern(pattern) {
// 如果pattern是数组,直接返回
if (Array.isArray(pattern)) {
return pattern;
......@@ -4379,7 +4555,7 @@ export default {
return [];
},
debounce (fn, delay = 300) {
debounce(fn, delay = 300) {
let timer = null;
return (...args) => {
if (timer) clearTimeout(timer);
......@@ -4389,7 +4565,7 @@ export default {
};
},
checkWidgetStatus () {
checkWidgetStatus() {
if (!this._seismicWidget) {
console.warn('Widget未初始化');
this.loadingError = 'Widget未初始化';
......@@ -4419,7 +4595,7 @@ export default {
},
// 修改边框圆角更新方法
handleBorderRadiusChange (value) {
handleBorderRadiusChange(value) {
// 确保值为数字
const radius = parseInt(value) || 0;
this.textStyle.borderRadius = radius;
......@@ -4427,13 +4603,13 @@ export default {
},
// 修改固定字体更新方法
handleFixedFontChange (value) {
handleFixedFontChange(value) {
this.textStyle.fixedFont = value;
this.updateAllStyles();
},
// 添加清除所有工具状态的方法
clearAllTools () {
clearAllTools() {
this.showTextStylePanel = false;
this.showLineStylePanel = false;
this.isDrawingText = false;
......@@ -4455,7 +4631,7 @@ export default {
},
// 修改请求重绘的方法
requestRepaint () {
requestRepaint() {
// 只调用有invalidate方法的对象
if (this._seismicWidget) {
this._seismicWidget.invalidate();
......@@ -4469,7 +4645,7 @@ export default {
},
// 添加更新选择视觉反馈的方法
updateSelectionVisualFeedback () {
updateSelectionVisualFeedback() {
// 更新所有形状的选中状态
if (this.annotationLayer) {
const children = this.annotationLayer.getChildren();
......@@ -4486,7 +4662,7 @@ export default {
},
// 添加切换颜色映射的方法
switchColorMap (colorMapName) {
switchColorMap(colorMapName) {
if (!this.pipeline || !this.colorProvider) {
console.error('Pipeline or colorProvider not initialized');
return;
......@@ -4537,7 +4713,7 @@ export default {
},
// 添加注册颜色映射的方法
registerColorMaps (colorProvider) {
registerColorMaps(colorProvider) {
if (!colorProvider) {
console.error('colorProvider为空,无法注册颜色映射');
return;
......@@ -4810,7 +4986,7 @@ export default {
}
},
toggleLineStylePanel () {
toggleLineStylePanel() {
// 如果工具已经激活,则停用
if (this.showLineStylePanel) {
this.deactivatePencilTool();
......@@ -4910,7 +5086,7 @@ export default {
this.pencilTool.setEnabled(true);
},
deactivatePencilTool () {
deactivatePencilTool() {
this.showLineStylePanel = false;
if (this.pencilTool) {
this.pencilTool.setEnabled(false);
......@@ -4928,15 +5104,15 @@ export default {
}
},
zoomIn () {
zoomIn() {
this.zoomScale = Math.min(this.zoomScale * 1.2, 6);
},
zoomOut () {
zoomOut() {
this.zoomScale = Math.max(this.zoomScale / 1.2, 0.2);
},
async exportToPDF (data) {
async exportToPDF(data) {
if (!this.plots || !this.isWidgetReady) {
this.$message.warning('请等待数据加载完成');
return;
......@@ -4957,7 +5133,7 @@ export default {
/**
* 显示右键菜单
*/
showContextMenu (event) {
showContextMenu(event) {
event.preventDefault();
// 获取当前活动的工具
......@@ -5001,7 +5177,7 @@ export default {
/**
* 隐藏右键菜单
*/
hideContextMenu () {
hideContextMenu() {
if (this.contextMenu.visible) {
this.contextMenu.visible = false;
this._contextMenuTool = null;
......@@ -5012,7 +5188,7 @@ export default {
/**
* 检查菜单项是否可用
*/
isMenuItemEnabled (action) {
isMenuItemEnabled(action) {
// 获取当前活动的工具
const tool = this._contextMenuTool;
......@@ -5038,7 +5214,7 @@ export default {
/**
* 处理菜单动作
*/
handleMenuAction (action) {
handleMenuAction(action) {
if (!this.isMenuItemEnabled(action)) return;
const tool = this._contextMenuTool;
......@@ -5080,7 +5256,7 @@ export default {
this.requestRepaint();
},
copyShape (tool) {
copyShape(tool) {
const shape = tool.getShape();
if (!shape) return;
......@@ -5090,7 +5266,7 @@ export default {
[shape.clone()];
},
pasteShape () {
pasteShape() {
if (!this.clipboard || this.clipboard.length === 0) return;
// 创建偏移量,以便粘贴的形状不会完全覆盖原始形状
......@@ -5112,7 +5288,7 @@ export default {
this.requestRepaint();
},
deleteShape (tool) {
deleteShape(tool) {
const shape = tool.getShape();
if (!shape) return;
......@@ -5138,7 +5314,7 @@ export default {
this.requestRepaint();
},
handleKeyDown (event) {
handleKeyDown(event) {
// 检查是否有活动的工具
const activeTool = this.pencilTool && this.pencilTool.isEnabled() ? this.pencilTool :
(this.annotationTool && this.annotationTool.isEnabled() ? this.annotationTool : null);
......@@ -5184,7 +5360,7 @@ export default {
},
// 添加一个新方法,用于切换形状的编辑状态
toggleShapeEditMode (shape) {
toggleShapeEditMode(shape) {
if (!shape) return;
// 获取活动工具
......@@ -5208,7 +5384,7 @@ export default {
this.requestRepaint();
},
getElementIcon (mdiIcon) {
getElementIcon(mdiIcon) {
// 将Vuetify的mdi图标转换为Element UI图标
const iconMap = {
'mdi-undo': 'el-icon-refresh-left',
......@@ -5222,19 +5398,19 @@ export default {
},
// 添加鼠标悬停相关事件
initCursorTools () {
initCursorTools() {
// 实现鼠标悬停相关事件的初始化逻辑
},
// 添加鼠标移动处理方法
handleMouseMove (event) {
handleMouseMove(event) {
if (!this._seismicWidget || !this.isHovering) return;
// 使用内置状态栏,不需要额外的处理逻辑
},
// 添加保存标注数据的方法
saveAnnotation (node) {
saveAnnotation(node) {
if (!node) {
console.warn('无法保存标注:节点为空');
return;
......@@ -5318,7 +5494,7 @@ export default {
},
// 添加恢复标注数据的方法
restoreAnnotations () {
restoreAnnotations() {
// 先恢复文本标注
if (!this.annotations || !this._seismicWidget || !this.savedAnnotations) {
console.warn('无法恢复标注:缺少必要组件', {
......@@ -5400,7 +5576,7 @@ export default {
},
// 添加恢复线条标注的方法
restoreLineAnnotations () {
restoreLineAnnotations() {
if (!this.annotations || !this._seismicWidget || !this.savedLineAnnotations) {
console.warn('无法恢复线条标注:缺少必要组件');
return;
......@@ -5473,7 +5649,7 @@ export default {
},
// 添加在指定位置创建文本的方法
createTextAtPosition () {
createTextAtPosition() {
if (!this._seismicWidget || !this.annotations) {
console.warn('Widget or annotations layer not ready');
return;
......@@ -5523,7 +5699,7 @@ export default {
},
// 添加新的辅助方法
detectChanges (previousState, currentNode) {
detectChanges(previousState, currentNode) {
if (!previousState || !currentNode) return {};
const changes = {};
......@@ -5580,7 +5756,7 @@ export default {
},
// 切换内部滚动条同步
toggleInternalScrollbarSync () {
toggleInternalScrollbarSync() {
this.internalScrollbarSyncEnabled = !this.internalScrollbarSyncEnabled;
if (this.internalScrollbarSyncEnabled) {
......@@ -5598,7 +5774,7 @@ export default {
}
},
beforeDestroy () {
beforeDestroy() {
// 如果缩略图容器被移动到body,销毁前移回组件内,避免遗留
try {
if (this.$refs && this.$refs.thumbContainer && this.$refs.thumbContainer.parentNode === document.body) {
......@@ -5697,6 +5873,11 @@ export default {
</script>
<style scoped>
.app-containers {
padding: 10px;
height: 90vh !important;
}
/* 顶部操作与缩略图 */
.top-actions {
display: flex;
......@@ -5726,15 +5907,20 @@ export default {
.right-thumb {
position: fixed;
/* 固定在视口右上角 */
top: 50px;
top: 150px;
right: 40px;
width: 280px;
background: #fff;
border: 1px solid rgba(0, 0, 0, 0.15);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15), 0 2px 8px rgba(0, 0, 0, 0.1);
z-index: 9999;
/* 确保在画布之上 */
border-radius: 4px;
transition: box-shadow 0.3s ease;
}
.right-thumb:hover {
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2), 0 4px 12px rgba(0, 0, 0, 0.15);
}
.thumb-title {
......@@ -5843,7 +6029,7 @@ export default {
.plot-canvas {
width: 100% !important;
height: calc(85vh - 35px) !important;
height: calc(85vh - 100px) !important;
margin-top: 20px;
transform-origin: top left;
}
......@@ -5854,7 +6040,7 @@ export default {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
flex-wrap: nowrap;
}
.toolbar-left {
......@@ -5869,9 +6055,204 @@ export default {
align-items: center;
gap: 15px;
margin-left: auto;
flex-wrap: nowrap;
white-space: nowrap;
}
/* 左侧操作按钮样式 - 现代渐变风格 */
.left-actions .el-button {
height: 32px;
padding: 0 14px;
border-radius: 6px;
border: none;
font-size: 12px;
font-weight: 500;
color: #fff;
background: linear-gradient(135deg, #409EFF 0%, #66b1ff 50%, #85c1ff 100%);
box-shadow: 0 2px 6px rgba(64, 158, 255, 0.25);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
letter-spacing: 0.3px;
}
.left-actions .el-button::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: left 0.5s ease;
}
.left-actions .el-button:hover {
background: linear-gradient(135deg, #337ecc 0%, #5a9eff 50%, #73b5ff 100%);
box-shadow: 0 6px 16px rgba(64, 158, 255, 0.35);
transform: translateY(-2px);
}
.left-actions .el-button:hover::before {
left: 100%;
}
.left-actions .el-button:active {
transform: translateY(0);
box-shadow: 0 2px 6px rgba(64, 158, 255, 0.25);
}
/* 右侧工具栏按钮样式 - 精致图标按钮 */
.toolbar-right .el-button {
width: 40px;
height: 40px;
padding: 0;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 0;
border: none;
background: linear-gradient(145deg, #f8f9fa 0%, #e9ecef 100%);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08),
inset 0 1px 0 rgba(255, 255, 255, 0.8);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
}
.toolbar-right .el-button [class^="el-icon-"] {
font-size: 16px;
margin: 0;
color: #6c757d;
transition: all 0.3s ease;
}
/* 绘制文本按钮 - 简化橙色系 */
.toolbar-right .el-button:has(.el-icon-edit-outline) [class^="el-icon-"] {
color: #ff8c00;
}
/* 统一按钮样式 */
.toolbar-right .el-button:has(.el-icon-edit-outline):hover {
background: linear-gradient(145deg, #ff8c00 0%, #ffa500 100%);
box-shadow: 0 4px 12px rgba(255, 140, 0, 0.25),
0 2px 4px rgba(0, 0, 0, 0.1);
}
.toolbar-right .el-button:has(.el-icon-edit-outline):hover [class^="el-icon-"] {
color: #fff;
}
.toolbar-right .el-button:has(.el-icon-edit-outline).active {
background: linear-gradient(145deg, #ff8c00 0%, #ffa500 100%);
box-shadow: 0 6px 16px rgba(255, 140, 0, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
.toolbar-right .el-button:has(.el-icon-edit-outline).active [class^="el-icon-"] {
color: #fff;
}
/* 绘制线条按钮 - 简化绿色系 */
.toolbar-right .el-button:has(.el-icon-edit) [class^="el-icon-"] {
color: #28a745;
}
.toolbar-right .el-button:has(.el-icon-edit):hover {
background: linear-gradient(145deg, #28a745 0%, #34ce57 100%);
box-shadow: 0 4px 12px rgba(40, 167, 69, 0.25),
0 2px 4px rgba(0, 0, 0, 0.1);
}
.toolbar-right .el-button:has(.el-icon-edit):hover [class^="el-icon-"] {
color: #fff;
}
.toolbar-right .el-button:has(.el-icon-edit).active {
background: linear-gradient(145deg, #28a745 0%, #34ce57 100%);
box-shadow: 0 6px 16px rgba(40, 167, 69, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
.toolbar-right .el-button:has(.el-icon-edit).active [class^="el-icon-"] {
color: #fff;
}
/* 同步按钮 - 紫色系 */
.toolbar-right .el-button:has(.el-icon-s-operation) {
background: linear-gradient(145deg, #f3e5f5 0%, #e1bee7 100%);
}
.toolbar-right .el-button:has(.el-icon-s-operation) [class^="el-icon-"] {
color: #9c27b0;
}
.toolbar-right .el-button:has(.el-icon-s-operation):hover {
background: linear-gradient(145deg, #9c27b0 0%, #ba68c8 100%);
box-shadow: 0 4px 12px rgba(156, 39, 176, 0.25),
0 2px 4px rgba(0, 0, 0, 0.1);
}
.toolbar-right .el-button:has(.el-icon-s-operation):hover [class^="el-icon-"] {
color: #fff;
}
.toolbar-right .el-button:has(.el-icon-s-operation).active {
background: linear-gradient(145deg, #9c27b0 0%, #ba68c8 100%);
box-shadow: 0 6px 16px rgba(156, 39, 176, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
.toolbar-right .el-button:has(.el-icon-s-operation).active [class^="el-icon-"] {
color: #fff;
}
.toolbar-right .el-button::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(145deg, #409EFF 0%, #66b1ff 100%);
opacity: 0;
transition: opacity 0.3s ease;
border-radius: 10px;
}
.toolbar-right .el-button:hover {
background: linear-gradient(145deg, #409EFF 0%, #66b1ff 100%);
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.25),
0 2px 4px rgba(0, 0, 0, 0.1);
transform: translateY(-1px);
}
.toolbar-right .el-button:hover::before {
opacity: 0;
}
.toolbar-right .el-button:hover [class^="el-icon-"] {
color: #fff;
transform: scale(1.1);
}
.toolbar-right .el-button.active {
background: linear-gradient(145deg, #409EFF 0%, #66b1ff 100%);
box-shadow: 0 6px 16px rgba(64, 158, 255, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.2);
transform: translateY(-1px);
}
.toolbar-right .el-button.active [class^="el-icon-"] {
color: #fff;
}
.toolbar-right .el-button:active {
transform: translateY(0);
box-shadow: 0 2px 6px rgba(64, 158, 255, 0.25);
}
/* 统一按钮样式 - 保持原有结构 */
.toolbar .el-button {
width: 40px;
height: 40px;
......@@ -5935,19 +6316,6 @@ export default {
display: none;
}
/* 鼠标悬停覆盖层样式 */
.hover-layer {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 5;
cursor: crosshair;
background-color: transparent;
pointer-events: none;
}
/* 样式面板相关样式 */
.style-panel {
position: fixed;
......
......@@ -116,9 +116,13 @@
<el-button size="mini" type="text" icon="el-icon-location"
@click="handleYsgcInfo(scope.row)">导航图</el-button>
</template>
<!-- 待验收状态:显示查看、井信息、segy信息和撤回按钮 -->
<!-- 待验收状态:显示查看、修改、删除、井信息、segy信息和撤回按钮 -->
<template v-else-if="scope.row.xmzt === '待验收'">
<el-button size="mini" type="text" icon="el-icon-view" @click="handleView(scope.row)">查看</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['ysqqXmxx:ysqqXmxx:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['ysqqXmxx:ysqqXmxx:remove']">删除</el-button>
<el-button size="mini" type="text" icon="el-icon-odometer" @click="handleJxxInfo(scope.row)">井信息</el-button>
<el-button size="mini" type="text" icon="el-icon-files"
@click="handleSegyInfo(scope.row)">segy信息</el-button>
......
......@@ -46,12 +46,14 @@
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
<el-button v-if="projectStatus === '未提交'" type="primary" plain icon="el-icon-plus" size="mini"
@click="handleAdd" v-hasPermi="['ysqqXmxxJxx:jxx:add']">新增</el-button>
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single || projectStatus !== '未提交'"
@click="handleUpdate" v-hasPermi="['ysqqXmxxJxx:jxx:edit']">修改</el-button>
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple || projectStatus !== '未提交'"
@click="handleDelete" v-hasPermi="['ysqqXmxxJxx:jxx:remove']">删除</el-button>
<el-button v-if="projectStatus === '未提交' || projectStatus === '待验收'" type="primary" plain icon="el-icon-plus"
size="mini" @click="handleAdd" v-hasPermi="['ysqqXmxxJxx:jxx:add']">新增</el-button>
<el-button type="success" plain icon="el-icon-edit" size="mini"
:disabled="single || (projectStatus !== '未提交' && projectStatus !== '待验收')" @click="handleUpdate"
v-hasPermi="['ysqqXmxxJxx:jxx:edit']">修改</el-button>
<el-button type="danger" plain icon="el-icon-delete" size="mini"
:disabled="multiple || (projectStatus !== '未提交' && projectStatus !== '待验收')" @click="handleDelete"
v-hasPermi="['ysqqXmxxJxx:jxx:remove']">删除</el-button>
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
v-hasPermi="['ysqqXmxxJxx:jxx:export']">导出</el-button>
</el-form-item>
......@@ -87,14 +89,14 @@
<el-table-column label="备用3" align="center" prop="ext3" /> -->
<el-table-column label="操作" min-width="100" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<!-- 未提交状态:显示修改和删除按钮 -->
<template v-if="projectStatus === '未提交'">
<!-- 未提交和待验收状态:显示修改和删除按钮 -->
<template v-if="projectStatus === '未提交' || projectStatus === '待验收'">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['ysqqXmxxJxx:jxx:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['ysqqXmxxJxx:jxx:remove']">删除</el-button>
</template>
<!-- 其他状态(待验收、已验收、已归档):只显示查看按钮 -->
<!-- 其他状态(已验收、已归档):只显示查看按钮 -->
<template v-else>
<el-button size="mini" type="text" icon="el-icon-view" @click="handleUpdate(scope.row)">查看</el-button>
</template>
......@@ -270,7 +272,7 @@ export default {
this.form = response.data
this.open = true
// 根据项目状态决定是查看还是修改
if (this.projectStatus === '未提交') {
if (this.projectStatus === '未提交' || this.projectStatus === '待验收') {
this.title = "修改验收前期-项目信息-井信息"
this.isReadOnly = false
} else {
......
......@@ -59,12 +59,14 @@
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
<el-button v-if="projectStatus === '未提交'" type="primary" plain icon="el-icon-plus" size="mini"
@click="handleAdd" v-hasPermi="['ysqqXmxxSegy:segy:add']">新增</el-button>
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single || projectStatus !== '未提交'"
@click="handleUpdate" v-hasPermi="['ysqqXmxxSegy:segy:edit']">修改</el-button>
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple || projectStatus !== '未提交'"
@click="handleDelete" v-hasPermi="['ysqqXmxxSegy:segy:remove']">删除</el-button>
<el-button v-if="projectStatus === '未提交' || projectStatus === '待验收'" type="primary" plain icon="el-icon-plus"
size="mini" @click="handleAdd" v-hasPermi="['ysqqXmxxSegy:segy:add']">新增</el-button>
<el-button type="success" plain icon="el-icon-edit" size="mini"
:disabled="single || (projectStatus !== '未提交' && projectStatus !== '待验收')" @click="handleUpdate"
v-hasPermi="['ysqqXmxxSegy:segy:edit']">修改</el-button>
<el-button type="danger" plain icon="el-icon-delete" size="mini"
:disabled="multiple || (projectStatus !== '未提交' && projectStatus !== '待验收')" @click="handleDelete"
v-hasPermi="['ysqqXmxxSegy:segy:remove']">删除</el-button>
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
v-hasPermi="['ysqqXmxxSegy:segy:export']">导出</el-button>
</el-form-item>
......@@ -101,14 +103,14 @@
<el-table-column label="备用3" align="center" prop="ext3" /> -->
<el-table-column label="操作" min-width="100" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<!-- 未提交状态:显示修改和删除按钮 -->
<template v-if="projectStatus === '未提交'">
<!-- 未提交和待验收状态:显示修改和删除按钮 -->
<template v-if="projectStatus === '未提交' || projectStatus === '待验收'">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['ysqqXmxxSegy:segy:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['ysqqXmxxSegy:segy:remove']">删除</el-button>
</template>
<!-- 其他状态(待验收、已验收、已归档):只显示查看按钮 -->
<!-- 其他状态(已验收、已归档):只显示查看按钮 -->
<template v-else>
<el-button size="mini" type="text" icon="el-icon-view" @click="handleUpdate(scope.row)">查看</el-button>
</template>
......@@ -343,7 +345,7 @@ export default {
this.open = true
// 根据项目状态决定是查看还是修改
if (this.projectStatus === '未提交') {
if (this.projectStatus === '未提交' || this.projectStatus === '待验收') {
this.title = "修改segy信息"
this.isReadOnly = false
} else {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment