Kaynağa Gözat

修改内容

yangg 3 hafta önce
ebeveyn
işleme
5bb3bd7e7a
1 değiştirilmiş dosya ile 75 ekleme ve 2 silme
  1. 75 2
      src/views/project/components/dataList.vue

+ 75 - 2
src/views/project/components/dataList.vue

@@ -582,6 +582,45 @@ export default {
       return tempDiv.innerHTML
     },
 
+    // 保证替换内容为内联且不换行:将 div/p 等块级标签转换为 span,并强制 white-space: nowrap
+    ensureInlineNoWrap(html) {
+      if (!html) return ''
+      try {
+        const wrapper = document.createElement('div')
+        wrapper.innerHTML = html
+
+        // 将所有 div/p 转为 span,保留原有内联样式
+        wrapper.querySelectorAll('div, p').forEach(block => {
+          const span = document.createElement('span')
+          // 复制子内容
+          while (block.firstChild) {
+            span.appendChild(block.firstChild)
+          }
+          // 合并样式并强制不换行与内联显示
+          const style = (block.getAttribute('style') || '')
+          span.setAttribute('style', `${style}${style.endsWith(';') ? '' : ';'} display: inline; white-space: nowrap;`)
+          // 替换节点
+          block.parentNode.replaceChild(span, block)
+        })
+
+        // 确保所有顶层文本不含多余换行或制表符
+        const normalizeTextNodes = (node) => {
+          node.childNodes && Array.from(node.childNodes).forEach(child => {
+            if (child.nodeType === Node.TEXT_NODE) {
+              child.textContent = child.textContent.replace(/[\t\r\n\f\v]+/g, ' ')
+            } else if (child.nodeType === Node.ELEMENT_NODE) {
+              normalizeTextNodes(child)
+            }
+          })
+        }
+        normalizeTextNodes(wrapper)
+
+        return wrapper.innerHTML
+      } catch (e) {
+        return typeof html === 'string' ? html : ''
+      }
+    },
+
     // 更新导出方法
     async exportDocumentWithHtmlDocx(template) {
       const res = await searchlistDocTemplate({
@@ -2293,14 +2332,15 @@ export default {
                 if (matchedContent?.content) {
                   // 构建替换内容
                   const cleanContent = matchedContent.content.trim() // 清理前后空格
+                  const inlineContent = this.ensureInlineNoWrap(cleanContent) // 转为内联且不换行
                   const chineseDescription = matchedContent.chinese_description || '' // 获取中文释义,如果有的话 !important
                   const formattedReplacement = `
                     <span 
                       class="replacement-content" 
                       data-code="${currentCode}" 
                       title="${chineseDescription}"
-                      style="background-color: #ffff00 !important; padding: 2px 4px; border-radius: 2px; display: inline-block;"
-                    >${cleanContent}${chineseDescription ? `<span class="chinese-desc" style="color: #67c23a; margin-left: 4px; font-size: 0.9em;">(${chineseDescription})</span>` : ''}</span>`.trim()
+                      style="background-color: #ffff00 !important; padding: 2px 4px; border-radius: 2px; display: inline; white-space: nowrap;"
+                    >${inlineContent}${chineseDescription ? `<span class="chinese-desc" style="color: #67c23a; margin-left: 4px; font-size: 0.9em;">(${chineseDescription})</span>` : ''}</span>`.trim()
 
                   // 处理表格和其他内容
                   updatedContent = this.processTableContent(
@@ -2354,6 +2394,8 @@ export default {
       if (!content || !searchItem) return content
 
       try {
+        // 确保传入 replacement 内部不包含导致换行的块级元素
+        replacement = this.ensureInlineNoWrap(replacement)
         // 提取搜索项中的编号
         const getCodeFromItem = (item) => {
           const cleanItem = item.replace(/[\[\]【】]/g, '')
@@ -2453,6 +2495,37 @@ export default {
           }
         }
         
+        // 在替换点前后去除多余空白并避免自动换行
+        tempDiv.querySelectorAll('span.replacement-content').forEach(span => {
+          // 去除包裹点两侧的多余空白文本节点
+          const trimSideWhitespace = (node, direction) => {
+            let sibling = direction === 'prev' ? node.previousSibling : node.nextSibling
+            while (sibling && sibling.nodeType === Node.TEXT_NODE) {
+              const trimmed = sibling.textContent.replace(/[\t\f\v\u00A0\u200B]+/g, ' ').replace(/\s+/g, ' ')
+              // 如果纯空白或只有一个空格,进一步根据上下文裁剪
+              if (!trimmed.trim()) {
+                const toRemove = sibling
+                sibling = direction === 'prev' ? sibling.previousSibling : sibling.nextSibling
+                toRemove.parentNode.removeChild(toRemove)
+              } else {
+                sibling.textContent = trimmed
+                // 剔除与替换点相邻的首尾空格,避免出现额外空格
+                if (direction === 'prev') sibling.textContent = sibling.textContent.replace(/[\s\u00A0]+$/, '')
+                else sibling.textContent = sibling.textContent.replace(/^[\s\u00A0]+/, '')
+                break
+              }
+            }
+          }
+          trimSideWhitespace(span, 'prev')
+          trimSideWhitespace(span, 'next')
+
+          // 强制不自动换行(若父元素限制导致换行,此设置可最大程度避免)
+          const currentStyle = span.getAttribute('style') || ''
+          if (!/white-space\s*:\s*nowrap/i.test(currentStyle)) {
+            span.setAttribute('style', `${currentStyle}${currentStyle.endsWith(';') ? '' : ';'} white-space: nowrap; display: inline;`)
+          }
+        })
+
         // 处理最终结果中的所有表格,确保自适应行高
         tempDiv.querySelectorAll('table').forEach(table => {
           // 添加自适应样式类