提交 58dd1d06 authored 作者: 安云鹏's avatar 安云鹏

修改 底部 侧边栏 分析 报文

上级 581d2dec
差异被折叠。
...@@ -50,7 +50,11 @@ if(route.path){ ...@@ -50,7 +50,11 @@ if(route.path){
navPath.value=route.path navPath.value=route.path
} }
const onNavListClick=(path)=>{ const onNavListClick=(path)=>{
if(path=='/writtingAsstaint'){
navPath.value=path navPath.value=path
}else{
ElMessage.error('正在开发中')
}
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
......
...@@ -295,12 +295,15 @@ export function useMarkdownStream() { ...@@ -295,12 +295,15 @@ export function useMarkdownStream() {
// 预处理内容 // 预处理内容
// const processedContent = preprocessMarkdown(rawContent.value) // const processedContent = preprocessMarkdown(rawContent.value)
let content = rawContent.value || '' let content = rawContent.value || ''
// 将 ==n== 转换为按钮样式的 HTML // 将 ==n== 转换为按钮样式的 HTML
// 使用正向预读和反向预读确保只匹配被 == 包裹的数字 // 使用正向预读和反向预读确保只匹配被 == 包裹的数字
content = content.replace(/==(\d+)==/g, (match, p1) => { // content = content.replace(/==(\d+)、==/g, (match, p1) => {
return `<button class="clause-ref-btn" data-clause="${p1}">${p1}</button>` // return `<button class="clause-ref-btn" data-clause="${p1}">${p1}</button>`
}) // })
content = content.replace(/==\s*(\d+)、.*?==/g, (match, p1) => {
return `<button class="clause-ref-btn" data-clause="${match.replace(/==/g, '') }">${p1}</button>`;
});
return md.render(content) return md.render(content)
}) })
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div class="writtingBottom"> <div class="writtingBottom">
<!-- 文档停止解析 --> <!-- 文档停止解析 -->
<div class="parsed" v-if="store.bottomProgressNum>0&&store.bottomProgressNum<100"> <div class="parsed" v-if="store.bottomProgressNum>0&&store.bottomProgressNum!=100&&store.writeProgressNum<10">
<div class="analysis" @click="store.resetGenerateState"> <div class="analysis" @click="store.resetGenerateState">
<div class="icon"></div> <div class="icon"></div>
<span class="text-tip-2-bold">停止</span> <span class="text-tip-2-bold">停止</span>
...@@ -10,7 +10,9 @@ ...@@ -10,7 +10,9 @@
<div class="progress"> <div class="progress">
<div class="login"> <div class="login">
<el-progress type="circle" :percentage="store.bottomProgressNum" :width="24" :height="24" style="margin-right: 15px;" :show-text="false" color="rgb(5, 95, 194)"/> <el-progress type="circle" :percentage="store.bottomProgressNum" :width="24" :height="24" style="margin-right: 15px;" :show-text="false" color="rgb(5, 95, 194)"/>
<span class="text-tip-2-bold">文档翻译中</span> <span class="text-tip-2-bold">
文档翻译中
</span>
</div> </div>
<div class="text-tip-2" > <div class="text-tip-2" >
<div ref="processContainerRef" v-html="renderedProcess"></div> <div ref="processContainerRef" v-html="renderedProcess"></div>
...@@ -21,7 +23,7 @@ ...@@ -21,7 +23,7 @@
<!-- 开始写报 --> <!-- 开始写报 -->
<!-- --> <!-- -->
<div class="parsed" v-else-if="store.bottomProgressNum>=100"> <div class="parsed" v-else-if="store.bottomProgressNum>=100">
<div class="analysis" v-if="store.isWriteStart&&store.writeProgressNum<100" @click="store.writeGenerateState"> <div class="analysis" v-if="store.writeProgressNum>0&&store.writeProgressNum!=100" @click="store.writeGenerateState">
<div class="icon"></div> <div class="icon"></div>
<span class="text-tip-2-bold">停止</span> <span class="text-tip-2-bold">停止</span>
</div> </div>
...@@ -35,10 +37,21 @@ ...@@ -35,10 +37,21 @@
</div> </div>
<div class="progress"> <div class="progress">
<div class="login"> <!-- 如果store.writeProgressNum>=1 点击了写报 否则是思维导图已完成 -->
<div class="login" v-if="store.writeProgressNum>=1&&store.writeProgressNum<100">
<el-progress type="circle" :percentage="store.writeProgressNum" :width="24" :height="24" style="margin-right: 15px;" :show-text="false" color="rgb(5, 95, 194)"/> <el-progress type="circle" :percentage="store.writeProgressNum" :width="24" :height="24" style="margin-right: 15px;" :show-text="false" color="rgb(5, 95, 194)"/>
<span class="text-tip-2-bold">智能写报中</span> <span class="text-tip-2-bold"> 智能写报中</span>
</div>
<div class="login" v-else-if="store.writeProgressNum>=100">
<el-icon style="width: 24px;height: 24px;margin-right: 4px;"><CircleCheckFilled style="width: 24px;height: 24px;" class="var(--color-primary-35)" /></el-icon>
<span class="text-tip-2-bold"> 文档解析完成</span>
</div>
<div class="login" v-else-if="store.bottomProgressNum>=100">
<el-icon style="width: 24px;height: 24px;margin-right: 4px;"><CircleCheckFilled style="width: 24px;height: 24px;" class="var(--color-primary-35)" /></el-icon>
<!-- <el-progress type="circle" :percentage="store.writeProgressNum" :width="24" :height="24" style="margin-right: 15px;" :show-text="false" color="rgb(5, 95, 194)"/> -->
<span class="text-tip-2-bold"> 思维导图已完成</span>
</div> </div>
<div class="text-tip-2" > <div class="text-tip-2" >
<div ref="processWriteLogRef" v-html="renderedProcess"> </div> <div ref="processWriteLogRef" v-html="renderedProcess"> </div>
</div> </div>
...@@ -76,6 +89,8 @@ const onAnalysisClick=()=>{ ...@@ -76,6 +89,8 @@ const onAnalysisClick=()=>{
} }
const onWriteClick=()=>{ const onWriteClick=()=>{
store.isShowSteps = false
emit("write"); emit("write");
} }
const { renderedProcess, updateProcess, clearContent } = useStream(); const { renderedProcess, updateProcess, clearContent } = useStream();
......
...@@ -159,7 +159,7 @@ ...@@ -159,7 +159,7 @@
<!-- </div> <!-- </div>
</div> --> </div> -->
<!-- 条款翻译侧边栏 srot --> <!-- 条款翻译侧边栏 srot -->
<div class="left-box translation-box" :class="{ 'has-back-btn': store.isGenerating }" v-if="store.isShowClauseTranslation&&store.headerTabType=='message'"> <div class="left-box translation-box" :class="{ 'has-back-btn': store.isGenerating }" v-if="store.isShowSteps&&store.headerTabType=='message'">
<div class="translation-main-box"> <div class="translation-main-box">
<!-- <div class="translation-actions" v-if="!store.isGenerating"> <!-- <div class="translation-actions" v-if="!store.isGenerating">
<div class="back-input-btn" @click="store.backToInputAndClear">返回输入栏</div> <div class="back-input-btn" @click="store.backToInputAndClear">返回输入栏</div>
...@@ -198,9 +198,9 @@ ...@@ -198,9 +198,9 @@
</div> </div>
</div> </div>
<!-- 步骤侧边栏显隐按钮 --> <!-- 步骤侧边栏显隐按钮 -->
<!-- <div class="toggle-steps-btn" @click="store.isShowSteps = !store.isShowSteps"> <div class="toggle-steps-btn" @click="store.isShowSteps = !store.isShowSteps">
<div class="arrow" :class="{ 'is-active': store.isShowSteps }"></div> <div class="arrow" :class="{ 'is-active': store.isShowSteps }"></div>
</div> --> </div>
</div> </div>
</div> </div>
</template> </template>
...@@ -245,16 +245,27 @@ watch( ...@@ -245,16 +245,27 @@ watch(
async (newId) => { async (newId) => {
if (!newId || !translationContentRef.value) return; if (!newId || !translationContentRef.value) return;
await nextTick(); await nextTick();
const container = translationContentRef.value; const container = translationContentRef.value;
const item = container.querySelector(`.translation-item[data-clause-number="${newId}"]`); const result = newId.replace(/^\d+、/, '');
const item = container.querySelector(`.translation-item[data-clause-number="${newId.match(/^(\d+)/)[1]}"]`);
const itemHtml=item.querySelector(`.translated-text`);
if (!item) return; if (!item) return;
// 你已经拿到的 外层大标签
const element =itemHtml
// 你要找的文字
const targetText = result
const location=findTextInElement(element, targetText);
const containerRect = container.getBoundingClientRect(); const containerRect = container.getBoundingClientRect();
const itemRect = item.getBoundingClientRect(); const itemRect = location;
const delta = itemRect.top - containerRect.top; const delta = itemRect.top - containerRect.top;
const targetTop = container.scrollTop + delta;
const targetTop = container.scrollTop + delta;
console.log(delta)
// 让高亮条款的“标题区域”贴到容器顶部 // 让高亮条款的“标题区域”贴到容器顶部
container.scrollTo({ container.scrollTo({
top: Math.max(0, targetTop), top: Math.max(0, targetTop),
...@@ -262,6 +273,77 @@ watch( ...@@ -262,6 +273,77 @@ watch(
}); });
} }
); );
// 👇 核心:在 element 内部找文字位置
// =========================================
function findTextInElement(element, targetText ) {
// 遍历标签内的所有内容
const nodes = element.childNodes;
let rect =''
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
// 只找纯文字
if (node.nodeType === 3) {
const originalText = node.textContent;
function cleanText(str) {
return str
.replace(/(/g, '(')
.replace(/)/g, ')')
.replace(/,/g, ',')
.replace(/。/g, '.')
.replace(/:/g, ':')
.replace(/;/g, ';');
}
// 清理后的文字(无标点)
const nodeClean = cleanText(originalText);
const targetClean = cleanText(targetText);
console.log(nodeClean)
console.log(targetClean)
console.log(nodeClean.includes(targetClean))
// 用干净文字对比
if (nodeClean.includes(targetClean)) {
// 找到真实位置(用原始文本定位,不影响)
const index = originalText.indexOf(
originalText.includes(targetText) ? targetText : originalText
);
const range = document.createRange();
range.setStart(node, index);
range.setEnd(node, index + targetText.length);
// 拿到位置
rect = range.getBoundingClientRect();
const marks = element.querySelectorAll('mark');
marks.forEach(mark => {
// 把 mark 里的文字放回原位,删除标签
const parent = mark.parentNode;
while (mark.firstChild) {
parent.insertBefore(mark.firstChild, mark);
}
parent.removeChild(mark);
// 合并相邻文本节点(恢复页面原貌)
parent.normalize();
});
const mark = document.createElement("mark");
mark.style.backgroundColor = '#055FC2';
mark.style.color = "#fff"; // 文字颜色
range.surroundContents(mark);
break;
}
}
}
return rect
}
// 监听 store.processLog 变化,更新步骤内容并滚动 // 监听 store.processLog 变化,更新步骤内容并滚动
watch( watch(
......
...@@ -42,6 +42,8 @@ const handleGlobalClick = (e) => { ...@@ -42,6 +42,8 @@ const handleGlobalClick = (e) => {
if (clauseId) { if (clauseId) {
store.highlightClauseId = clauseId; store.highlightClauseId = clauseId;
// 翻译栏一直显示,所以这里只需要确保它在视图内 // 翻译栏一直显示,所以这里只需要确保它在视图内
store.isShowSteps = true;
console.log(store.highlightClauseId )
} }
} }
}; };
...@@ -88,6 +90,7 @@ watch( ...@@ -88,6 +90,7 @@ watch(
}, },
{ immediate: true } { immediate: true }
); );
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
......
...@@ -33,24 +33,25 @@ ...@@ -33,24 +33,25 @@
<div class="writting-main"> <div class="writting-main">
<!-- 左侧子组件:绑定ref --> <!-- 左侧子组件:绑定ref -->
<!-- <writtingleftBox ref="leftBoxRef" @generate="handleGenerate" /> --> <!-- <writtingleftBox ref="leftBoxRef" @generate="handleGenerate" /> -->
<!-- <writtingleftBox ref="leftBoxRef" /> --> <WrittingLeftBox ref="leftBoxRef" />
<!-- 翻译 --> <!-- 翻译 -->
<!-- <WrittingTranslate v-if="store.isShowClauseTranslation&&store.headerTabType=='translate'"></WrittingTranslate> --> <WrittingTranslate v-if="store.isShowClauseTranslation&&store.headerTabType=='translate'"></WrittingTranslate>
<!-- 思维导图 v-else-if="store.isShowClauseTranslation&&store.headerTabType=='mind'"--> <!-- 思维导图 " -->
<WrittingMind ></WrittingMind> <WrittingMind v-else-if="store.isShowClauseTranslation&&store.headerTabType=='mind' "></WrittingMind>
<!-- 写报 --> <!-- 写报 -->
<!-- <WrittingMessage v-else-if="store.isShowClauseTranslation&&store.headerTabType=='message'"></WrittingMessage> --> <WrittingMessage v-else-if="store.isShowClauseTranslation&&store.headerTabType=='message'"></WrittingMessage>
<!-- 无数据时显示占位图 --> <!-- 无数据时显示占位图 -->
<!-- <div v-else class="main-placeholder"> <div v-else class="main-placeholder">
<img src="./assets/images/container-image.png" alt="无数据占位图" /> <img src="./assets/images/container-image.png" alt="无数据占位图" />
<div class="placeholder-text"> <div class="placeholder-text">
<div v-if="store.isGenerating">智能体写报任务执行中...</div> <div v-if="store.isGenerating">智能体写报任务执行中...</div>
<div v-else>上传文件后点击“生成报文”开始写报...</div> <div v-else>上传文件后点击“生成报文”开始写报...</div>
</div> </div>
</div> --> </div>
<!-- 右侧子组件:绑定ref --> <!-- 右侧子组件:绑定ref -->
<!-- <writtingMainBox v-show="!!store.reportContent" ref="mainBoxRef" :report-content="store.reportContent" /> --> <!-- <writtingMainBox v-show="!!store.reportContent" ref="mainBoxRef" :report-content="store.reportContent" /> -->
...@@ -66,7 +67,7 @@ import { onMounted, onUnmounted, ref, nextTick } from "vue"; ...@@ -66,7 +67,7 @@ import { onMounted, onUnmounted, ref, nextTick } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { useWrittingAsstaintStore } from "@/stores/writtingAsstaintStore"; import { useWrittingAsstaintStore } from "@/stores/writtingAsstaintStore";
import writtingleftBox from "./components/WrittingLeftBox.vue"; import WrittingLeftBox from "./components/WrittingLeftBox.vue";
import WrittingHeader from "./components/WrittingHeader.vue"; //头 import WrittingHeader from "./components/WrittingHeader.vue"; //头
import WrittingBottom from "./components/WrittingBottom.vue"; //底部 import WrittingBottom from "./components/WrittingBottom.vue"; //底部
...@@ -105,11 +106,12 @@ const handleGenerate = async () => { ...@@ -105,11 +106,12 @@ const handleGenerate = async () => {
}; };
const handleWrite=async ()=>{ const handleWrite=async ()=>{
try { try {
console.log(1)
// // 等待DOM更新(确保子组件DOM已挂载) // // 等待DOM更新(确保子组件DOM已挂载)
store.tabList[2].active=true //写报生成之后放开写报按钮
store.headerTabType='translate'
await nextTick(); await nextTick();
await store.generateWrite() await store.generateWrite()
console.log(2)
} catch (error) { } catch (error) {
ElMessage.error(error.message); ElMessage.error(error.message);
console.error("生成写报失败:", error); console.error("生成写报失败:", error);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论