Commit 435f623c by zhaopanyu

zpy

parent d3b7283d
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
<el-button size="small" @click="setHorizontalLayout">左右结构</el-button> <el-button size="small" @click="setHorizontalLayout">左右结构</el-button>
<el-button size="small" @click="handlePrevTrace">上一道</el-button> <el-button size="small" @click="handlePrevTrace">上一道</el-button>
<el-button size="small" @click="handleNextTrace">下一道</el-button> <el-button size="small" @click="handleNextTrace">下一道</el-button>
<el-button type="primary" @click="submitSegyAnnotations">保存标注
<i class="el-icon-check"></i>
</el-button>
</div> </div>
<!-- 右侧按钮组(与左侧同一行,靠右对齐) --> <!-- 右侧按钮组(与左侧同一行,靠右对齐) -->
<div class="toolbar-right"> <div class="toolbar-right">
...@@ -41,9 +44,7 @@ ...@@ -41,9 +44,7 @@
</el-button> </el-button>
</el-tooltip> </el-tooltip>
<el-tooltip content="保存标注" placement="bottom" effect="light"> <el-tooltip content="保存标注" placement="bottom" effect="light">
<el-button type="primary" @click="submitSegyAnnotations">
<i class="el-icon-check"></i>
</el-button>
</el-tooltip> </el-tooltip>
<!-- <el-tooltip :content="internalScrollbarSyncEnabled ? '内部滚动条同步已启用' : '内部滚动条同步已禁用'" placement="bottom" <!-- <el-tooltip :content="internalScrollbarSyncEnabled ? '内部滚动条同步已启用' : '内部滚动条同步已禁用'" placement="bottom"
effect="light"> effect="light">
...@@ -956,9 +957,6 @@ export default { ...@@ -956,9 +957,6 @@ export default {
// 图形设置 // 图形设置
showPropertiesDialog: false, showPropertiesDialog: false,
listNameColorMaps: [ listNameColorMaps: [
"WhiteBlack", "WhiteBlack",
"RedWhiteBlack", "RedWhiteBlack",
...@@ -1258,15 +1256,190 @@ export default { ...@@ -1258,15 +1256,190 @@ export default {
window.removeEventListener('resize', this.updateBaseCanvasSize); window.removeEventListener('resize', this.updateBaseCanvasSize);
}, },
methods: { methods: {
// 深度序列化 properties 对象,将复杂对象转换为可序列化的格式
serializeProperties(props) {
if (!props || typeof props !== 'object') return {}
const result = {}
try {
for (const key in props) {
if (!props.hasOwnProperty(key)) continue
const value = props[key]
// 跳过函数和 undefined
if (typeof value === 'function' || value === undefined) continue
// 特殊处理 text 字段 - 确保文本内容被正确保留
if (key === 'text') {
if (value !== null && value !== undefined) {
const textValue = String(value)
// 即使文本为空字符串,也保留它(因为可能是用户有意设置的)
result[key] = textValue
continue
} else {
result[key] = null
continue
}
}
// 处理 null
if (value === null) {
result[key] = null
continue
}
// 处理基本类型
if (typeof value !== 'object') {
result[key] = value
continue
}
// 处理数组
if (Array.isArray(value)) {
result[key] = value.map(item => {
if (typeof item === 'object' && item !== null) {
return this.serializeProperties(item)
}
return item
})
continue
}
// 处理复杂对象 - 尝试提取可序列化的属性
try {
// 如果对象有常见的方法,尝试调用它们获取值
const serialized = this.serializeProperties(value)
if (value.getColor && typeof value.getColor === 'function') {
try {
serialized.color = value.getColor()
} catch (e) { }
}
if (value.getFont && typeof value.getFont === 'function') {
try {
serialized.font = value.getFont()
} catch (e) { }
}
if (value.getAlignment && typeof value.getAlignment === 'function') {
try {
serialized.alignment = value.getAlignment()
} catch (e) { }
}
result[key] = serialized
} catch (e) {
// 如果序列化失败,尝试 JSON.stringify/parse 来提取可序列化的部分
try {
const str = JSON.stringify(value)
result[key] = JSON.parse(str)
} catch (e2) {
// 如果都失败,记录对象的所有可枚举属性
const simpleObj = {}
for (const k in value) {
if (value.hasOwnProperty(k)) {
const v = value[k]
if (typeof v !== 'function' && v !== undefined) {
if (typeof v === 'object' && v !== null && !Array.isArray(v)) {
simpleObj[k] = this.serializeProperties(v)
} else {
simpleObj[k] = v
}
}
}
}
result[key] = simpleObj
}
}
}
} catch (e) {
console.warn('[serializeProperties] error:', e)
}
return result
},
// 将一个绘制节点序列化为简易对象 // 将一个绘制节点序列化为简易对象
serializeNode(node) { serializeNode(node) {
if (!node) return null if (!node) return null
const props = typeof node.getProperties === 'function' ? node.getProperties() : {}
if (typeof node.getText === 'function' || typeof props.text === 'string' || node.text) { // ========== 关键修复:在序列化之前先提取文本 ==========
const text = typeof node.getText === 'function' ? node.getText() : (node.text || props.text || '') let extractedText = ''
return { type: 'text', text, properties: props || {} }
// 方法1: 直接访问 node.text
try {
const directText = node.text
if (directText !== undefined && directText !== null && String(directText).trim() !== '') {
extractedText = String(directText)
console.log('[serializeNode] ✓ 从 node.text 直接获取文本:', extractedText)
}
} catch (e) {
console.warn('[serializeNode] 读取 node.text 失败:', e)
}
// 方法2: 尝试 getText() 方法
if (!extractedText || extractedText.trim() === '') {
try {
if (typeof node.getText === 'function') {
const methodText = node.getText()
if (methodText !== undefined && methodText !== null && String(methodText).trim() !== '') {
extractedText = String(methodText)
console.log('[serializeNode] ✓ 从 getText() 获取文本:', extractedText)
}
}
} catch (e) {
console.warn('[serializeNode] getText() 调用失败:', e)
}
}
// 方法3: 从 getProperties() 获取
let props = {}
try {
props = typeof node.getProperties === 'function' ? node.getProperties() : {}
if (!extractedText && props && props.text !== undefined && props.text !== null) {
const propsText = String(props.text)
if (propsText.trim() !== '') {
extractedText = propsText
console.log('[serializeNode] ✓ 从 getProperties().text 获取文本:', extractedText)
}
}
} catch (e) {
console.warn('[serializeNode] getProperties error:', e)
}
// 深度序列化 properties
const serializedProps = this.serializeProperties(props)
// 如果已经提取到文本,强制设置到 serializedProps 中
if (extractedText && extractedText.trim() !== '') {
serializedProps.text = extractedText
console.log('[serializeNode] ✓ 已强制设置 serializedProps.text =', extractedText)
}
if (typeof node.getText === 'function' || extractedText || serializedProps.text || node.text) {
// 使用已经提取的文本
const text = extractedText || (serializedProps.text ? String(serializedProps.text) : '')
if (!text || text.trim() === '') {
console.warn('[serializeNode] ⚠️ 警告:文本节点但 text 为空!', {
node,
extractedText,
serializedPropsText: serializedProps.text
})
}
// 获取文本样式
let textStyle = null
try {
const tstyle = typeof node.getTextStyle === 'function' ? node.getTextStyle() : null
if (tstyle) {
textStyle = {
font: tstyle.getFont && typeof tstyle.getFont === 'function' ? tstyle.getFont() : (tstyle.font || tstyle.lH),
color: tstyle.getColor && typeof tstyle.getColor === 'function' ? tstyle.getColor() : (tstyle.color || tstyle.Lx),
size: tstyle.size || tstyle.eZ,
alignment: tstyle.getAlignment && typeof tstyle.getAlignment === 'function' ? tstyle.getAlignment() : (tstyle.alignment || tstyle.Vf)
}
}
} catch (e) {
console.warn('[serializeNode] getTextStyle error:', e)
} }
return { type: 'path', properties: props || {} } return {
type: 'text',
text,
properties: serializedProps,
textStyle: textStyle
}
}
return { type: 'path', properties: serializedProps }
}, },
// 获取所有需要提交的标注节点(包含图层中的节点和当前工具正在编辑的节点) // 获取所有需要提交的标注节点(包含图层中的节点和当前工具正在编辑的节点)
getAllAnnotationNodes() { getAllAnnotationNodes() {
...@@ -1318,38 +1491,174 @@ export default { ...@@ -1318,38 +1491,174 @@ export default {
collectAnnotationData() { collectAnnotationData() {
const result = [] const result = []
try { try {
// 首先尝试使用缓存的标注数据
if (Array.isArray(this.collectedAnnotations) && this.collectedAnnotations.length > 0) {
console.log('[collectAnnotationData] 使用缓存的标注数据,数量:', this.collectedAnnotations.length);
// 过滤掉 _nodeRef 字段,只保留可序列化的数据
const cachedData = this.collectedAnnotations.map(item => {
const { _nodeRef, ...cleanItem } = item;
return cleanItem;
});
return cachedData;
}
const nodes = this.getAllAnnotationNodes() const nodes = this.getAllAnnotationNodes()
if (!Array.isArray(nodes) || nodes.length === 0) return result if (!Array.isArray(nodes) || nodes.length === 0) {
console.log('[collectAnnotationData] 未找到节点,返回空数组');
return result;
}
for (const node of nodes) { for (const node of nodes) {
const props = typeof node.getProperties === 'function' ? node.getProperties() : {} if (!node) continue
// 文本
// ========== 关键修复:在序列化之前先提取文本 ==========
// 必须先提取文本,因为序列化可能会丢失数据
let extractedText = ''
// 优先检查缓存中是否有该节点的文本
const cachedItem = Array.isArray(this.collectedAnnotations)
? this.collectedAnnotations.find(item => item._nodeRef === node)
: null;
if (cachedItem && cachedItem.text && String(cachedItem.text).trim() !== '') {
extractedText = String(cachedItem.text);
console.log('[collectAnnotationData] ✓ 从缓存获取文本:', extractedText);
}
// 方法1: 直接访问 node.text(最直接的方式)
try {
const directText = node.text
if (directText !== undefined && directText !== null && String(directText).trim() !== '') {
extractedText = String(directText)
console.log('[collectAnnotationData] ✓ 从 node.text 直接获取文本:', extractedText)
}
} catch (e) {
console.warn('[collectAnnotationData] 读取 node.text 失败:', e)
}
// 方法2: 尝试 getText() 方法
if (!extractedText || extractedText.trim() === '') {
try {
if (typeof node.getText === 'function') { if (typeof node.getText === 'function') {
const text = node.getText() const methodText = node.getText()
if (methodText !== undefined && methodText !== null && String(methodText).trim() !== '') {
extractedText = String(methodText)
console.log('[collectAnnotationData] ✓ 从 getText() 获取文本:', extractedText)
}
}
} catch (e) {
console.warn('[collectAnnotationData] getText() 调用失败:', e)
}
}
// 方法3: 从 getProperties() 获取(但要立即读取,不要等序列化)
if (!extractedText || extractedText.trim() === '') {
try {
if (typeof node.getProperties === 'function') {
const rawProps = node.getProperties()
if (rawProps && rawProps.text !== undefined && rawProps.text !== null) {
const propsText = String(rawProps.text)
if (propsText.trim() !== '') {
extractedText = propsText
console.log('[collectAnnotationData] ✓ 从 getProperties().text 获取文本:', extractedText)
}
}
}
} catch (e) {
console.warn('[collectAnnotationData] getProperties() 调用失败:', e)
}
}
// 现在获取 properties 进行序列化
let props = {}
try {
props = typeof node.getProperties === 'function' ? node.getProperties() : {}
} catch (e) {
console.warn('[collectAnnotationData] getProperties error:', e)
}
// 深度序列化 properties
const serializedProps = this.serializeProperties(props)
// 如果已经提取到文本,强制设置到 serializedProps 中
if (extractedText && extractedText.trim() !== '') {
serializedProps.text = extractedText
console.log('[collectAnnotationData] ✓ 已强制设置 serializedProps.text =', extractedText)
}
// 文本节点处理
if (typeof node.getText === 'function' || extractedText || serializedProps.text || node.text) {
// 使用已经提取的文本,如果为空则使用序列化后的
const text = extractedText || (serializedProps.text ? String(serializedProps.text) : '')
console.log('[collectAnnotationData] 最终文本提取结果:', {
extractedText,
serializedPropsText: serializedProps.text,
finalText: text,
nodeText: node.text,
propsText: props.text
})
// 确保文本不为空
if (!text || text.trim() === '') {
console.warn('[collectAnnotationData] ⚠️ 警告:文本节点但 text 为空!', {
node,
extractedText,
serializedPropsText: serializedProps.text,
propsText: props.text
})
}
// 获取文本样式
let textStyle = null
try {
const tstyle = typeof node.getTextStyle === 'function' ? node.getTextStyle() : null const tstyle = typeof node.getTextStyle === 'function' ? node.getTextStyle() : null
if (tstyle) {
textStyle = {
font: tstyle.getFont && typeof tstyle.getFont === 'function' ? tstyle.getFont() : (tstyle.font || tstyle.lH),
color: tstyle.getColor && typeof tstyle.getColor === 'function' ? tstyle.getColor() : (tstyle.color || tstyle.Lx),
size: tstyle.size || tstyle.eZ,
alignment: tstyle.getAlignment && typeof tstyle.getAlignment === 'function' ? tstyle.getAlignment() : (tstyle.alignment || tstyle.Vf)
}
}
} catch (e) {
console.warn('[collectAnnotationData] getTextStyle error:', e)
}
// 再次确保 serializedProps.text 有值
if (text && text.trim() !== '') {
serializedProps.text = text
}
result.push({ result.push({
type: 'text', type: 'text',
text, text: text || '', // 确保至少是空字符串而不是 undefined
properties: props || {}, properties: serializedProps,
style: tstyle ? { textStyle: textStyle
font: tstyle.getFont && tstyle.getFont(),
color: tstyle.getColor && tstyle.getColor(),
size: tstyle.size,
alignment: tstyle.getAlignment && tstyle.getAlignment()
} : null
}) })
} else { } else {
// 线条/路径(Paint工具创建的Path) // 线条/路径(Paint工具创建的Path)
result.push({ result.push({
type: 'path', type: 'path',
properties: props || {} properties: serializedProps
}) })
} }
} }
} catch (e) { } catch (e) {
// 忽略 console.error('[collectAnnotationData] error:', e)
} }
try { try {
console.log('[collect] result length:', result.length, 'sample:', result.slice(0, 2)) console.log('[collect] result length:', result.length, 'sample:', result.slice(0, 2))
// 打印每个结果的详细信息用于调试
result.forEach((item, index) => {
console.log(`[collect] item#${index}:`, {
type: item.type,
text: item.text,
hasText: !!item.text,
textLength: item.text ? item.text.length : 0,
propertiesKeys: Object.keys(item.properties || {}),
hasTextInProps: !!item.properties?.text
})
})
} catch (e) { } } catch (e) { }
return result return result
}, },
...@@ -1403,6 +1712,57 @@ export default { ...@@ -1403,6 +1712,57 @@ export default {
} }
} catch (e) { } } catch (e) { }
} }
// 后处理:确保所有文本项的 text 字段都被正确填充
if (Array.isArray(bznr) && bznr.length > 0) {
bznr = bznr.map((item, index) => {
if (item.type === 'text') {
console.log(`[submitSegyAnnotations] 后处理文本项 #${index}:`, {
text: item.text,
textType: typeof item.text,
textLength: item.text ? item.text.length : 0,
propertiesText: item.properties?.text,
propertiesTextType: typeof item.properties?.text,
propertiesKeys: Object.keys(item.properties || {})
})
// 如果 text 为空,尝试从 properties.text 获取
if (!item.text || String(item.text).trim() === '') {
if (item.properties && item.properties.text !== undefined && item.properties.text !== null) {
const propsText = String(item.properties.text)
if (propsText.trim() !== '') {
item.text = propsText
console.log(`[submitSegyAnnotations] 从 properties.text 恢复文本 #${index}:`, item.text)
}
}
}
// 确保 text 是字符串类型且不为空
if (item.text !== undefined && item.text !== null) {
item.text = String(item.text)
// 如果仍然是空字符串,记录警告
if (item.text.trim() === '') {
console.warn(`[submitSegyAnnotations] 警告:文本项 #${index} 的 text 字段为空字符串!`, {
item,
properties: item.properties
})
}
} else {
console.warn(`[submitSegyAnnotations] 警告:文本项 #${index} 的 text 字段为 undefined 或 null!`, item)
}
// 确保 properties.text 也有值
if (item.text && item.text.trim() !== '') {
if (!item.properties) {
item.properties = {}
}
item.properties.text = item.text
}
}
return item
})
}
// 打印准备提交的关键信息 // 打印准备提交的关键信息
try { try {
const counts = (Array.isArray(bznr) ? bznr.reduce((acc, it) => { acc[it.type] = (acc[it.type] || 0) + 1; return acc }, {}) : {}) const counts = (Array.isArray(bznr) ? bznr.reduce((acc, it) => { acc[it.type] = (acc[it.type] || 0) + 1; return acc }, {}) : {})
...@@ -1411,21 +1771,80 @@ export default { ...@@ -1411,21 +1771,80 @@ export default {
console.log('[submitSegyAnnotations] segyid:', seg && seg.id, 'fullSeg:', seg) console.log('[submitSegyAnnotations] segyid:', seg && seg.id, 'fullSeg:', seg)
console.log('[submitSegyAnnotations] annotations count:', counts, 'total:', Array.isArray(bznr) ? bznr.length : 0) console.log('[submitSegyAnnotations] annotations count:', counts, 'total:', Array.isArray(bznr) ? bznr.length : 0)
console.log('[submitSegyAnnotations] annotations sample:', Array.isArray(bznr) ? bznr.slice(0, 2) : bznr) console.log('[submitSegyAnnotations] annotations sample:', Array.isArray(bznr) ? bznr.slice(0, 2) : bznr)
// 详细检查每个文本项的 text 字段
if (Array.isArray(bznr)) {
bznr.forEach((item, index) => {
if (item.type === 'text') {
console.log(`[submitSegyAnnotations] text item#${index}:`, {
hasText: !!item.text,
text: item.text,
textLength: item.text ? item.text.length : 0,
hasTextInProps: !!item.properties?.text,
propsText: item.properties?.text
})
}
})
}
} catch (e) { } } catch (e) { }
if (!bznr || bznr.length === 0) { if (!bznr || bznr.length === 0) {
this.$message.warning('没有可提交的标注数据') this.$message.warning('没有可提交的标注数据')
return return
} }
const list = [{ // 将线条和文本分开处理
const lines = [] // 线条数组
const texts = [] // 文本数组
bznr.forEach(item => {
if (item.type === 'path') {
// 线条类型
lines.push(item)
} else if (item.type === 'text') {
// 文本类型
texts.push(item)
}
})
// 构建提交列表
const list = []
// 为每个线条创建独立的数组项
lines.forEach(line => {
list.push({
xmid: xmid, xmid: xmid,
segyid: seg.id, segyid: seg.id,
lx: '新版', lx: '新版',
bznr: JSON.stringify(bznr) ext1: '线条',
}] bznr: JSON.stringify([line])
})
})
// 为每个文本创建独立的数组项
texts.forEach(text => {
list.push({
xmid: xmid,
segyid: seg.id,
lx: '新版',
ext1: '文本',
bznr: JSON.stringify([text])
})
})
if (list.length === 0) {
this.$message.warning('没有可提交的标注数据')
return
}
await addAllSegyDz(list) await addAllSegyDz(list)
this.$message.success('标注提交成功') this.$message.success('标注提交成功')
// 保存成功后调用 toDht 接口
try {
await toDht(xmid)
console.log('[submitSegyAnnotations] toDht 接口调用成功')
} catch (e) {
console.error('[submitSegyAnnotations] toDht 接口调用失败:', e)
}
} catch (e) { } catch (e) {
this.$message.error('标注提交失败') this.$message.error('标注提交失败')
} }
...@@ -1650,11 +2069,304 @@ export default { ...@@ -1650,11 +2069,304 @@ export default {
} }
// <-- 自动标注还原 // <-- 自动标注还原
// ysqqXmxxSegy 可能才是原始数据数组 // 优先使用 handleFileSelect 中从 toDht 接口获取并保存的 ysqqXmxxSegy 数据
let segList = (Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0) ? this.ysqqXmxxSegy : this.segyList; let segList = (Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0)
? this.ysqqXmxxSegy // 优先使用从 toDht 接口获取的原始数据
: this.segyList; // 兜底使用 segyList
const originSegy = segList[this.currentSegyIndex] || segList[0]; const originSegy = segList[this.currentSegyIndex] || segList[0];
console.log('[loadCurrentSegy] 准备恢复标注,使用数据源:',
Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0 ? 'ysqqXmxxSegy' : 'segyList',
'originSegy:', originSegy);
await this.renderAnnotationsFromXbbznr(originSegy); await this.renderAnnotationsFromXbbznr(originSegy);
}, },
// 从接口返回的 xbbznr 数据中解析并恢复标注
async renderAnnotationsFromXbbznr(originSegy) {
try {
console.log('[renderAnnotationsFromXbbznr] 开始执行,originSegy:', originSegy);
console.log('[renderAnnotationsFromXbbznr] currentSegyIndex:', this.currentSegyIndex);
console.log('[renderAnnotationsFromXbbznr] ysqqXmxxSegy:', this.ysqqXmxxSegy);
console.log('[renderAnnotationsFromXbbznr] segyList:', this.segyList);
if (!originSegy) {
console.log('[renderAnnotationsFromXbbznr] originSegy 为空,跳过恢复');
return;
}
let xbbznr = originSegy.xbbznr;
console.log('[renderAnnotationsFromXbbznr] xbbznr 原始值1233333:', xbbznr);
console.log('[renderAnnotationsFromXbbznr] xbbznr 类型333333:', typeof xbbznr);
// 如果 xbbznr 是字符串,需要解析为对象
if (xbbznr && typeof xbbznr === 'string') {
try {
xbbznr = JSON.parse(xbbznr);
console.log('[renderAnnotationsFromXbbznr] JSON 解析成功,xbbznr:', xbbznr);
} catch (e) {
console.warn('[renderAnnotationsFromXbbznr] JSON 解析失败:', e);
console.warn('[renderAnnotationsFromXbbznr] 解析失败的 xbbznr 内容:', xbbznr);
return;
}
}
console.log('[renderAnnotationsFromXbbznr] 解析后的 xbbznr:', xbbznr, '类型:', typeof xbbznr, '是否为数组:', Array.isArray(xbbznr));
if (!xbbznr) {
console.log('[renderAnnotationsFromXbbznr] xbbznr 为空,跳过恢复');
return;
}
// xbbznr 现在应该是解析后的对象或数组
let annotationList = [];
// 如果已经是数组,直接使用;如果是对象,尝试转换为数组
if (Array.isArray(xbbznr)) {
annotationList = xbbznr;
console.log('[renderAnnotationsFromXbbznr] xbbznr 是数组,直接使用,长度:', annotationList.length);
} else if (typeof xbbznr === 'object' && xbbznr !== null) {
// 如果是对象,尝试转换为数组
annotationList = [xbbznr];
console.log('[renderAnnotationsFromXbbznr] xbbznr 是对象,转换为数组,长度:', annotationList.length);
} else {
console.warn('[renderAnnotationsFromXbbznr] xbbznr 不是有效的数组或对象:', xbbznr, '类型:', typeof xbbznr);
return;
}
console.log('[renderAnnotationsFromXbbznr] JSON 解析成功,annotationList:', annotationList);
console.log('[renderAnnotationsFromXbbznr] annotationList 类型:', Array.isArray(annotationList) ? 'Array' : typeof annotationList);
console.log('[renderAnnotationsFromXbbznr] annotationList 长度:', annotationList.length);
if (!Array.isArray(annotationList) || annotationList.length === 0) {
console.log('[renderAnnotationsFromXbbznr] 标注列表为空,跳过恢复', {
isArray: Array.isArray(annotationList),
length: annotationList ? annotationList.length : 0,
annotationList: annotationList
});
return;
}
console.log('[renderAnnotationsFromXbbznr] 开始解析标注数据,数量:', annotationList.length);
console.log('[renderAnnotationsFromXbbznr] annotationList 详细内容:', JSON.stringify(annotationList, null, 2));
// 清空现有的 savedAnnotations 和 savedLineAnnotations
this.savedAnnotations = [];
this.savedLineAnnotations = [];
// 转换数据格式并存储到对应的数组
console.log('[renderAnnotationsFromXbbznr] 开始转换数据,annotationList 长度:', annotationList.length);
annotationList.forEach((item, index) => {
try {
console.log(`[renderAnnotationsFromXbbznr] 处理第 ${index + 1} 项:`, {
ext1: item.ext1,
hasBznr: !!item.bznr,
item: item
});
// 检查是否有 ext1 和 bznr 字段(新格式)
if (item.ext1 && item.bznr) {
// 新格式:根据 ext1 字段判断类型
let bznrData = null;
try {
// 解析 bznr(可能是字符串或已经是数组)
if (typeof item.bznr === 'string') {
bznrData = JSON.parse(item.bznr);
} else if (Array.isArray(item.bznr)) {
bznrData = item.bznr;
} else {
bznrData = [item.bznr];
}
} catch (e) {
console.error(`[renderAnnotationsFromXbbznr] 解析 bznr 失败 #${index + 1}:`, e);
return;
}
// 确保 bznrData 是数组
if (!Array.isArray(bznrData)) {
bznrData = [bznrData];
}
if (item.ext1 === '文本') {
// 处理文本标注
bznrData.forEach((bznrItem, bznrIndex) => {
if (bznrItem.type === 'text') {
// 提取文本内容
const text = bznrItem.text || bznrItem.properties?.text || '';
console.log(`[renderAnnotationsFromXbbznr] 提取的文本: "${text}"`);
// 转换 properties 格式
const properties = { ...bznrItem.properties };
console.log(`[renderAnnotationsFromXbbznr] 原始 properties:`, properties);
// 处理 textstyle - 转换格式
if (bznrItem.properties && bznrItem.properties.textstyle) {
properties.textstyle = bznrItem.properties.textstyle;
} else if (bznrItem.textStyle) {
properties.textstyle = {
Lx: bznrItem.textStyle.color || '#000000',
lH: bznrItem.textStyle.font || '22px Sans-serif',
Vf: bznrItem.textStyle.alignment || 'left',
eZ: bznrItem.textStyle.size || '22px'
};
} else {
properties.textstyle = {
Lx: '#000000',
lH: '22px Sans-serif',
Vf: 'left',
eZ: '22px'
};
}
properties.text = text;
if (!properties.linestyle) {
properties.linestyle = {
Lx: '#0351ad',
fA: 2
};
}
if (!properties.fillstyle) {
properties.fillstyle = {
Lx: '#c7e1f6'
};
}
const annotationData = {
text: text,
properties: properties
};
this.savedAnnotations.push(annotationData);
console.log(`[renderAnnotationsFromXbbznr] ✓ 已转换文本标注 #${index + 1}-${bznrIndex + 1}:`, {
text: annotationData.text,
hasProperties: !!annotationData.properties
});
}
});
} else if (item.ext1 === '线条') {
// 处理线条标注
bznrData.forEach((bznrItem, bznrIndex) => {
if (bznrItem.type === 'path') {
const lineData = {
properties: bznrItem.properties || {}
};
this.savedLineAnnotations.push(lineData);
console.log(`[renderAnnotationsFromXbbznr] ✓ 已转换线条标注 #${index + 1}-${bznrIndex + 1}`);
}
});
}
} else {
// 旧格式兼容:直接处理 item(保持向后兼容)
if (item.type === 'text') {
const text = item.text || item.properties?.text || '';
const properties = { ...item.properties };
if (item.properties && item.properties.textstyle) {
properties.textstyle = item.properties.textstyle;
} else if (item.textStyle) {
properties.textstyle = {
Lx: item.textStyle.color || '#000000',
lH: item.textStyle.font || '22px Sans-serif',
Vf: item.textStyle.alignment || 'left',
eZ: item.textStyle.size || '22px'
};
} else {
properties.textstyle = {
Lx: '#000000',
lH: '22px Sans-serif',
Vf: 'left',
eZ: '22px'
};
}
properties.text = text;
if (!properties.linestyle) {
properties.linestyle = {
Lx: '#0351ad',
fA: 2
};
}
if (!properties.fillstyle) {
properties.fillstyle = {
Lx: '#c7e1f6'
};
}
const annotationData = {
text: text,
properties: properties
};
this.savedAnnotations.push(annotationData);
console.log(`[renderAnnotationsFromXbbznr] ✓ 已转换文本标注(旧格式) #${index + 1}`);
} else if (item.type === 'path') {
const lineData = {
properties: item.properties || {}
};
this.savedLineAnnotations.push(lineData);
console.log(`[renderAnnotationsFromXbbznr] ✓ 已转换线条标注(旧格式) #${index + 1}`);
}
}
} catch (error) {
console.error(`[renderAnnotationsFromXbbznr] 转换标注 #${index + 1} 时出错:`, error);
}
});
console.log('[renderAnnotationsFromXbbznr] 转换完成,savedAnnotations 数量:', this.savedAnnotations.length, 'savedLineAnnotations 数量:', this.savedLineAnnotations.length);
console.log('[renderAnnotationsFromXbbznr] savedAnnotations 完整数据:', JSON.stringify(this.savedAnnotations, null, 2));
console.log('[renderAnnotationsFromXbbznr] savedLineAnnotations 完整数据:', JSON.stringify(this.savedLineAnnotations, null, 2));
// 等待组件就绪后恢复标注
if (this.savedAnnotations.length > 0 || this.savedLineAnnotations.length > 0) {
// 确保 annotations 层已创建
if (!this.annotations && this._seismicWidget) {
this.annotations = new Group();
const manip = this._seismicWidget.getManipulatorLayer && this._seismicWidget.getManipulatorLayer();
const layer = manip || this._seismicWidget.getOverlayLayer();
if (layer) {
layer.addChild(this.annotations);
this.annotations.setVisible(true);
}
} else if (this.annotations) {
// 清空现有的标注节点,避免重复
try {
const children = this.annotations.getChildren ? this.annotations.getChildren() : [];
children.forEach(child => {
try {
if (child.dispose && typeof child.dispose === 'function') {
child.dispose();
}
} catch (e) {
console.warn('[renderAnnotationsFromXbbznr] 清理节点失败:', e);
}
});
this.annotations.removeAllChildren && this.annotations.removeAllChildren();
console.log('[renderAnnotationsFromXbbznr] 已清空现有标注节点');
} catch (e) {
console.warn('[renderAnnotationsFromXbbznr] 清空标注层失败:', e);
}
}
// 延迟恢复,确保图表已加载完成
this.$nextTick(() => {
setTimeout(() => {
if (this.savedAnnotations.length > 0) {
this.restoreAnnotations();
console.log('[renderAnnotationsFromXbbznr] 文本标注恢复完成,共恢复', this.savedAnnotations.length, '个标注');
}
if (this.savedLineAnnotations.length > 0) {
this.restoreLineAnnotations();
console.log('[renderAnnotationsFromXbbznr] 线条标注恢复完成,共恢复', this.savedLineAnnotations.length, '个标注');
}
}, 500);
});
}
} catch (error) {
console.error('[renderAnnotationsFromXbbznr] 处理 xbbznr 数据时出错:', error);
}
},
// 清空当前图表 // 清空当前图表
clearCurrentPlots() { clearCurrentPlots() {
//console.log('[index2] 清空当前图表'); //console.log('[index2] 清空当前图表');
...@@ -1866,7 +2578,6 @@ export default { ...@@ -1866,7 +2578,6 @@ export default {
attempts.unshift({ url: rawUrl, headers }); attempts.unshift({ url: rawUrl, headers });
attempts.push({ url: rawUrl }); attempts.push({ url: rawUrl });
} }
const errors = []; const errors = [];
for (const attempt of attempts) { for (const attempt of attempts) {
try { try {
...@@ -4431,6 +5142,12 @@ export default { ...@@ -4431,6 +5142,12 @@ export default {
if (segys.length === 0) { if (segys.length === 0) {
throw new Error('未找到 SEGY 数据'); throw new Error('未找到 SEGY 数据');
} }
// 保存 segys 数据到组件状态,供后续恢复标注使用
this.ysqqXmxxSegy = segys;
this.segyList = segys;
this.currentSegyIndex = 0; // 重置为第一个
console.log('[handleFileSelect] 已保存 ysqqXmxxSegy 数据,数量:', segys.length);
} catch (error) { } catch (error) {
console.error('[handleFileSelect] 获取数据失败:', error); console.error('[handleFileSelect] 获取数据失败:', error);
this.loadingError = `获取数据失败: ${error.message}`; this.loadingError = `获取数据失败: ${error.message}`;
...@@ -4597,6 +5314,26 @@ export default { ...@@ -4597,6 +5314,26 @@ export default {
// 最终确认内部滚动条被禁用 // 最终确认内部滚动条被禁用
this.setScrollbarCSS(this._seismicWidget); this.setScrollbarCSS(this._seismicWidget);
this.forceDisableInternalScrollbars(); this.forceDisableInternalScrollbars();
// 文件加载完成后,恢复标注
// 使用从 toDht 接口获取并保存的 ysqqXmxxSegy 数据
this.$nextTick(() => {
setTimeout(() => {
// 优先使用从 toDht 接口获取的 ysqqXmxxSegy 数据(包含 xbbznr 字段)
let segList = (Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0)
? this.ysqqXmxxSegy // 使用从 toDht 接口获取的原始数据
: this.segyList; // 兜底使用 segyList
const originSegy = segList[this.currentSegyIndex] || segList[0];
if (originSegy) {
console.log('[handleFileSelect] 准备恢复标注,使用数据源:',
Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0 ? 'ysqqXmxxSegy' : 'segyList',
'originSegy:', originSegy);
this.renderAnnotationsFromXbbznr(originSegy);
} else {
console.warn('[handleFileSelect] 未找到 originSegy,无法恢复标注');
}
}, 500);
});
}, 1000); }, 1000);
}, 500); }, 500);
resolve(); resolve();
...@@ -4730,18 +5467,61 @@ export default { ...@@ -4730,18 +5467,61 @@ export default {
}) })
.addListener(EditEvents.End, (tool, node) => { .addListener(EditEvents.End, (tool, node) => {
if (node) { if (node) {
// 修复:按优先级提取文本,即使前面的方法返回空也要继续尝试
let text = ''; let text = '';
// 方法1: 优先从 node.text 直接属性获取(最可靠)
if (node.text !== undefined && node.text !== null && String(node.text).trim() !== '') {
text = String(node.text);
console.log('[annotationTool][End] ✓ 从 node.text 获取文本:', text);
}
// 方法2: 如果 node.text 为空,尝试 getText() 方法
if (!text || text.trim() === '') {
try {
if (typeof node.getText === 'function') { if (typeof node.getText === 'function') {
text = node.getText(); const methodText = node.getText();
} else if (node.text) { if (methodText !== undefined && methodText !== null && String(methodText).trim() !== '') {
text = node.text; text = String(methodText);
} else if (node.getProperties && node.getProperties().text) { console.log('[annotationTool][End] ✓ 从 getText() 获取文本:', text);
text = node.getProperties().text; }
}
} catch (e) {
console.warn('[annotationTool][End] getText() 调用失败:', e);
}
}
// 方法3: 如果还是为空,尝试从 properties 中获取
if (!text || text.trim() === '') {
try {
if (node.getProperties && typeof node.getProperties === 'function') {
const props = node.getProperties();
if (props && props.text !== undefined && props.text !== null && String(props.text).trim() !== '') {
text = String(props.text);
console.log('[annotationTool][End] ✓ 从 properties.text 获取文本:', text);
}
}
} catch (e) {
console.warn('[annotationTool][End] getProperties() 调用失败:', e);
}
}
// 如果文本为空,记录警告
if (!text || text.trim() === '') {
console.warn('[annotationTool][End] ⚠️ 警告:文本节点但 text 为空!', {
node,
nodeText: node.text,
hasGetText: typeof node.getText === 'function',
getTextResult: typeof node.getText === 'function' ? node.getText() : 'N/A',
properties: node.getProperties ? node.getProperties() : null
});
} }
const textStyle = node.getTextStyle ? node.getTextStyle() : null; const textStyle = node.getTextStyle ? node.getTextStyle() : null;
console.log('[annotationTool][End] 绘制文本节点', { console.log('[annotationTool][End] 绘制文本节点', {
node, node,
text, text,
nodeText: node.text,
properties: node.getProperties && node.getProperties(), properties: node.getProperties && node.getProperties(),
textStyle: textStyle ? { textStyle: textStyle ? {
font: textStyle.getFont && textStyle.getFont(), font: textStyle.getFont && textStyle.getFont(),
...@@ -4750,6 +5530,58 @@ export default { ...@@ -4750,6 +5530,58 @@ export default {
alignment: textStyle.getAlignment && textStyle.getAlignment() alignment: textStyle.getAlignment && textStyle.getAlignment()
} : null } : null
}); });
// 关键修复:如果获取到文本,立即缓存并同步到节点
if (text && text.trim() !== '') {
try {
// 1. 同步文本到 properties
const props = node.getProperties ? node.getProperties() : {};
if (!props.text || String(props.text).trim() === '') {
if (typeof node.setProperties === 'function') {
node.setProperties({ ...props, text: text });
console.log('[annotationTool][End] ✓ 已同步文本到 properties.text:', text);
}
}
// 2. 立即缓存到 collectedAnnotations(使用节点引用作为标识)
try {
// 检查是否已存在相同节点的缓存
const existingIndex = this.collectedAnnotations.findIndex(item => item._nodeRef === node);
const cacheItem = {
type: 'text',
text: text,
properties: node.getProperties ? node.getProperties() : {},
textStyle: textStyle ? {
font: textStyle.getFont && textStyle.getFont(),
color: textStyle.getColor && textStyle.getColor(),
size: textStyle.size,
alignment: textStyle.getAlignment && textStyle.getAlignment()
} : null,
_nodeRef: node // 保存节点引用用于后续匹配
};
if (existingIndex >= 0) {
// 更新现有缓存
this.collectedAnnotations[existingIndex] = cacheItem;
console.log('[annotationTool][End] ✓ 已更新缓存项 #' + existingIndex, text);
} else {
// 添加新缓存
this.collectedAnnotations.push(cacheItem);
console.log('[annotationTool][End] ✓ 已缓存文本到 collectedAnnotations:', text, '总数:', this.collectedAnnotations.length);
}
} catch (e) {
console.warn('[annotationTool][End] 缓存失败:', e);
}
} catch (e) {
console.warn('[annotationTool][End] 同步文本到 properties 失败:', e);
}
}
// 确保节点被添加到图层
if (this.annotations.indexOfChild(node) === -1) {
this.annotations.addChild(node);
console.log('[annotationTool][End] ✓ 已添加节点到图层');
}
} }
this.requestRepaint(); this.requestRepaint();
}); });
...@@ -4892,19 +5724,61 @@ export default { ...@@ -4892,19 +5724,61 @@ export default {
this.annotationTool.addListener(EditEvents.End, (tool, node) => { this.annotationTool.addListener(EditEvents.End, (tool, node) => {
if (node) { if (node) {
// 修复:按优先级提取文本,即使前面的方法返回空也要继续尝试
let text = ''; let text = '';
// 方法1: 优先从 node.text 直接属性获取(最可靠)
if (node.text !== undefined && node.text !== null && String(node.text).trim() !== '') {
text = String(node.text);
console.log('[annotationTool][End] ✓ 从 node.text 获取文本:', text);
}
// 方法2: 如果 node.text 为空,尝试 getText() 方法
if (!text || text.trim() === '') {
try {
if (typeof node.getText === 'function') { if (typeof node.getText === 'function') {
text = node.getText(); const methodText = node.getText();
} else if (node.text) { if (methodText !== undefined && methodText !== null && String(methodText).trim() !== '') {
text = node.text; text = String(methodText);
} else if (node.getProperties && node.getProperties().text) { console.log('[annotationTool][End] ✓ 从 getText() 获取文本:', text);
text = node.getProperties().text; }
}
} catch (e) {
console.warn('[annotationTool][End] getText() 调用失败:', e);
}
}
// 方法3: 如果还是为空,尝试从 properties 中获取
if (!text || text.trim() === '') {
try {
if (node.getProperties && typeof node.getProperties === 'function') {
const props = node.getProperties();
if (props && props.text !== undefined && props.text !== null && String(props.text).trim() !== '') {
text = String(props.text);
console.log('[annotationTool][End] ✓ 从 properties.text 获取文本:', text);
}
}
} catch (e) {
console.warn('[annotationTool][End] getProperties() 调用失败:', e);
}
}
// 如果文本为空,记录警告
if (!text || text.trim() === '') {
console.warn('[annotationTool][End] ⚠️ 警告:文本节点但 text 为空!', {
node,
nodeText: node.text,
hasGetText: typeof node.getText === 'function',
getTextResult: typeof node.getText === 'function' ? node.getText() : 'N/A',
properties: node.getProperties ? node.getProperties() : null
});
} }
const textStyle = node.getTextStyle ? node.getTextStyle() : null; const textStyle = node.getTextStyle ? node.getTextStyle() : null;
console.log('[annotationTool][End] 绘制文本节点', { console.log('[annotationTool][End] 绘制文本节点', {
node, node,
text, text,
nodeText: node.text,
properties: node.getProperties && node.getProperties(), properties: node.getProperties && node.getProperties(),
textStyle: textStyle ? { textStyle: textStyle ? {
font: textStyle.getFont && textStyle.getFont(), font: textStyle.getFont && textStyle.getFont(),
...@@ -4913,6 +5787,58 @@ export default { ...@@ -4913,6 +5787,58 @@ export default {
alignment: textStyle.getAlignment && textStyle.getAlignment() alignment: textStyle.getAlignment && textStyle.getAlignment()
} : null } : null
}); });
// 关键修复:如果获取到文本,立即缓存并同步到节点
if (text && text.trim() !== '') {
try {
// 1. 同步文本到 properties
const props = node.getProperties ? node.getProperties() : {};
if (!props.text || String(props.text).trim() === '') {
if (typeof node.setProperties === 'function') {
node.setProperties({ ...props, text: text });
console.log('[annotationTool][End] ✓ 已同步文本到 properties.text:', text);
}
}
// 2. 立即缓存到 collectedAnnotations(使用节点引用作为标识)
try {
// 检查是否已存在相同节点的缓存
const existingIndex = this.collectedAnnotations.findIndex(item => item._nodeRef === node);
const cacheItem = {
type: 'text',
text: text,
properties: node.getProperties ? node.getProperties() : {},
textStyle: textStyle ? {
font: textStyle.getFont && textStyle.getFont(),
color: textStyle.getColor && textStyle.getColor(),
size: textStyle.size,
alignment: textStyle.getAlignment && textStyle.getAlignment()
} : null,
_nodeRef: node // 保存节点引用用于后续匹配
};
if (existingIndex >= 0) {
// 更新现有缓存
this.collectedAnnotations[existingIndex] = cacheItem;
console.log('[annotationTool][End] ✓ 已更新缓存项 #' + existingIndex, text);
} else {
// 添加新缓存
this.collectedAnnotations.push(cacheItem);
console.log('[annotationTool][End] ✓ 已缓存文本到 collectedAnnotations:', text, '总数:', this.collectedAnnotations.length);
}
} catch (e) {
console.warn('[annotationTool][End] 缓存失败:', e);
}
} catch (e) {
console.warn('[annotationTool][End] 同步文本到 properties 失败:', e);
}
}
// 确保节点被添加到图层
if (this.annotations.indexOfChild(node) === -1) {
this.annotations.addChild(node);
console.log('[annotationTool][End] ✓ 已添加节点到图层');
}
} }
this.requestRepaint(); this.requestRepaint();
}); });
...@@ -6236,9 +7162,9 @@ export default { ...@@ -6236,9 +7162,9 @@ export default {
} }
try { try {
// console.log('开始恢复文本标注:', { console.log('[restoreAnnotations] 开始恢复文本标注,savedAnnotations 数量:', this.savedAnnotations.length);
// totalAnnotations: this.savedAnnotations.length console.log('[restoreAnnotations] savedAnnotations 完整数据:', JSON.stringify(this.savedAnnotations, null, 2));
// }); console.log('[restoreAnnotations] savedAnnotations 对象:', this.savedAnnotations);
// 恢复文本标注 // 恢复文本标注
this.savedAnnotations.forEach((data, index) => { this.savedAnnotations.forEach((data, index) => {
...@@ -6997,9 +7923,9 @@ export default { ...@@ -6997,9 +7923,9 @@ export default {
} }
.plot-canvas { .plot-canvas {
width: 100% !important; /* width: 100% !important; */
height: calc(85vh - 100px) !important; height: calc(85vh - 100px) !important;
margin-top: 20px; /* margin-top: 20px; */
transform-origin: top left; transform-origin: top left;
} }
......
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