Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
ea3442f9
提交
ea3442f9
authored
1月 26, 2026
作者:
张伊明
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
修复窗口视角后重新提交请求的bug
上级
a6ad2831
隐藏空白字符变更
内嵌
并排
正在显示
1 个修改的文件
包含
390 行增加
和
418 行删除
+390
-418
index.vue
src/views/writtingAsstaint/index.vue
+390
-418
没有找到文件。
src/views/writtingAsstaint/index.vue
浏览文件 @
ea3442f9
<
template
>
<div
class=
"writting-wrapper"
>
<div
class=
"writting-header"
>
<div
class=
"tab-box"
>
<div
class=
"tab"
:class=
"
{ tabActive: item.active }"
v-for="(item, index) in tabList"
:key="index">
{{
item
.
name
}}
</div>
</div>
<div
class=
"edit-box"
></div>
<div
class=
"btn-box"
>
<div
class=
"btn"
@
click=
"exportContent"
>
<div
class=
"icon"
>
<img
src=
"./assets/images/export-icon.png"
alt=
""
/>
</div>
<div
class=
"text"
>
{{
"导出"
}}
</div>
</div>
<div
class=
"btn"
@
click=
"handleSwitchMode"
>
<div
class=
"icon"
>
<img
v-if=
"isEditMode"
src=
"./assets/images/preview-icon.png"
alt=
""
/>
<img
v-else
src=
"./assets/images/edit.png"
alt=
""
/>
</div>
<div
class=
"text"
>
{{
isEditMode
?
"预览"
:
"编辑"
}}
</div>
</div>
<div
class=
"btn btn1"
>
<div
class=
"icon"
>
<img
src=
"./assets/images/save-icon.png"
alt=
""
/>
</div>
<div
class=
"text text1"
>
{{
"保存"
}}
</div>
</div>
</div>
</div>
<div
class=
"writting-main"
>
<div
class=
"left-box"
>
<div
class=
"process-box"
v-if=
"isShowProcess"
>
<div
class=
"back"
@
click=
"handleBack"
>
{{
"< 返回"
}}
</div>
<div
class=
"process-main-box"
>
<div
class=
"steps-box"
>
<div
class=
"steps-header"
>
<div
class=
"icon"
>
<img
src=
"./assets/images/right-arrow.png"
alt=
""
/>
</div>
<div
class=
"text"
>
{{
"执行步骤:"
}}
</div>
</div>
<div
class=
"steps-content"
ref=
"scrollProcessContainer"
v-html=
"renderedProcess"
></div>
</div>
<div
class=
"tool-box"
>
<div
class=
"tool-header"
>
{{
"工具调用"
}}
</div>
<div
class=
"tool-main"
>
当前智能体工具:
{{
curAgentTool
?
curAgentTool
:
"无"
}}
</div>
</div>
</div>
</div>
<div
class=
"sider"
v-else
>
<div
class=
"sider-box"
v-if=
"false"
>
<div
class=
"header"
>
报文主题
</div>
<div
class=
"title-box"
>
<div
class=
"title"
>
主题名称
</div>
<el-input
:disabled=
"true"
style=
"width: 476px; height: 32px"
class=
"title-input"
placeholder=
"输入主题名称,如:大而美法案"
v-model=
"writtingTitle"
/>
</div>
<div
class=
"description-box"
>
<div
class=
"title"
>
主题描述
</div>
<el-input
:disabled=
"true"
class=
"description-input"
type=
"textarea"
style=
"width: 476px"
:rows=
"8"
placeholder=
"输入报文主题描述,如:从科技领域方面分析大而美法案通过后对中国可能产生的影响"
v-model=
"descText"
/>
</div>
</div>
<div
class=
"sider-box"
>
<div
class=
"header"
>
报文模板
</div>
<div
class=
"template-box"
>
<div
class=
"template"
:class=
"
{ tempActive: tempActiveIndex === index }"
v-for="(temp, index) in tempList"
:key="index"
@click="handleClickTemp(temp, index)">
<div
class=
"header"
>
<div
class=
"title"
>
{{
temp
.
title
}}
</div>
<div
class=
"icon"
>
<img
src=
"./assets/images/template-icon.png"
alt=
""
/>
</div>
</div>
<div
class=
"content"
>
{{
temp
.
desc
}}
</div>
<div
class=
"active-icon"
v-if=
"tempActiveIndex === index"
>
<img
src=
"./assets/images/active-icon.png"
alt=
""
/>
</div>
<div
class=
"selected-icon"
v-if=
"tempActiveIndex === index"
>
<img
src=
"./assets/images/selected-icon.png"
alt=
""
/>
</div>
</div>
</div>
</div>
<div
class=
"sider-box"
>
<div
class=
"header"
>
加载本地文件
</div>
<el-upload
action=
""
:auto-upload=
"false"
accept=
".pdf"
limit=
"1"
:on-exceed=
"handleExceed"
ref=
"upload"
:on-change=
"handleFileChange"
>
<el-button
class=
"sider-upload-btn"
type=
"primary"
>
<el-icon
class=
"sider-upload-btn-text"
>
<Upload
/>
</el-icon>
<span
class=
"sider-upload-btn-text"
>
上传文件
</span>
</el-button>
<template
#
tip
>
<div
class=
"sider-upload-btn-tip"
>
支持扩展名:.doc .docx .pdf
</div>
</
template
>
</el-upload>
</div>
</div>
<div
class=
"submit-area"
>
<div
class=
"tips"
>
<div
class=
"tips-icon"
>
<img
src=
"./assets/images/tips-icon.png"
alt=
""
/>
</div>
<div
class=
"tips-text"
>
内容由AI生成,无法确保真实准确,仅供参考
</div>
</div>
<div
class=
"process-footer-box"
v-if=
"isShowProcess"
>
<div
class=
"footer-left"
>
{{ isGenerating ? "报文生成中..." : "报文已生成" }}
</div>
<div
class=
"footer-right"
>
<div
class=
"icon"
></div>
<div
class=
"text"
@
click=
"handleGenerate"
>
{{ "停止" }}
</div>
</div>
</div>
<div
class=
"submit-btn"
@
click=
"getStreamChat"
v-else
>
<div
class=
"submit-icon"
>
<img
src=
"./assets/images/ai.png"
alt=
""
/>
</div>
<div
class=
"submit-text"
>
生成报文
</div>
</div>
</div>
</div>
<div
class=
"main-box"
>
<div
v-if=
"isEditMode"
class=
"edit-panel"
>
<v-md-editor
v-model=
"reportContent"
height=
"calc(100% - 40px)"
:disabled-menus=
"[]"
@
upload-image=
"handleUploadImage"
@
save=
"handleSave"
left-toolbar=
"undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save"
right-toolbar=
"preview toc sync-scroll fullscreen"
/>
</div>
<div
v-else
class=
"content-box"
ref=
"scrollContainer"
v-html=
"renderedContent"
></div>
</div>
</div>
</div>
<div
class=
"writting-wrapper"
>
<div
class=
"writting-header"
>
<div
class=
"tab-box"
>
<div
class=
"tab"
:class=
"
{ tabActive: item.active }" v-for="(item, index) in tabList" :key="index">
{{
item
.
name
}}
</div>
</div>
<div
class=
"edit-box"
></div>
<div
class=
"btn-box"
>
<div
class=
"btn"
@
click=
"exportContent"
>
<div
class=
"icon"
>
<img
src=
"./assets/images/export-icon.png"
alt=
""
/>
</div>
<div
class=
"text"
>
{{
"导出"
}}
</div>
</div>
<div
class=
"btn"
@
click=
"handleSwitchMode"
>
<div
class=
"icon"
>
<img
v-if=
"isEditMode"
src=
"./assets/images/preview-icon.png"
alt=
""
/>
<img
v-else
src=
"./assets/images/edit.png"
alt=
""
/>
</div>
<div
class=
"text"
>
{{
isEditMode
?
"预览"
:
"编辑"
}}
</div>
</div>
<div
class=
"btn btn1"
>
<div
class=
"icon"
>
<img
src=
"./assets/images/save-icon.png"
alt=
""
/>
</div>
<div
class=
"text text1"
>
{{
"保存"
}}
</div>
</div>
</div>
</div>
<div
class=
"writting-main"
>
<div
class=
"left-box"
>
<div
class=
"process-box"
v-if=
"isShowProcess"
>
<div
class=
"back"
@
click=
"handleBack"
>
{{
"< 返回"
}}
</div>
<div
class=
"process-main-box"
>
<div
class=
"steps-box"
>
<div
class=
"steps-header"
>
<div
class=
"icon"
>
<img
src=
"./assets/images/right-arrow.png"
alt=
""
/>
</div>
<div
class=
"text"
>
{{
"执行步骤:"
}}
</div>
</div>
<div
class=
"steps-content"
ref=
"scrollProcessContainer"
v-html=
"renderedProcess"
></div>
</div>
<div
class=
"tool-box"
>
<div
class=
"tool-header"
>
{{
"工具调用"
}}
</div>
<div
class=
"tool-main"
>
当前智能体工具:
{{
curAgentTool
?
curAgentTool
:
"无"
}}
</div>
</div>
</div>
</div>
<div
class=
"sider"
v-else
>
<div
class=
"sider-box"
v-if=
"false"
>
<div
class=
"header"
>
报文主题
</div>
<div
class=
"title-box"
>
<div
class=
"title"
>
主题名称
</div>
<el-input
:disabled=
"true"
style=
"width: 476px; height: 32px"
class=
"title-input"
placeholder=
"输入主题名称,如:大而美法案"
v-model=
"writtingTitle"
/>
</div>
<div
class=
"description-box"
>
<div
class=
"title"
>
主题描述
</div>
<el-input
:disabled=
"true"
class=
"description-input"
type=
"textarea"
style=
"width: 476px"
:rows=
"8"
placeholder=
"输入报文主题描述,如:从科技领域方面分析大而美法案通过后对中国可能产生的影响"
v-model=
"descText"
/>
</div>
</div>
<div
class=
"sider-box"
>
<div
class=
"header"
>
报文模板
</div>
<div
class=
"template-box"
>
<div
class=
"template"
:class=
"
{ tempActive: tempActiveIndex === index }"
v-for="(temp, index) in tempList"
:key="index"
@click="handleClickTemp(temp, index)"
>
<div
class=
"header"
>
<div
class=
"title"
>
{{
temp
.
title
}}
</div>
<div
class=
"icon"
>
<img
src=
"./assets/images/template-icon.png"
alt=
""
/>
</div>
</div>
<div
class=
"content"
>
{{
temp
.
desc
}}
</div>
<div
class=
"active-icon"
v-if=
"tempActiveIndex === index"
>
<img
src=
"./assets/images/active-icon.png"
alt=
""
/>
</div>
<div
class=
"selected-icon"
v-if=
"tempActiveIndex === index"
>
<img
src=
"./assets/images/selected-icon.png"
alt=
""
/>
</div>
</div>
</div>
</div>
<div
class=
"sider-box"
>
<div
class=
"header"
>
加载本地文件
</div>
<el-upload
action=
""
:auto-upload=
"false"
accept=
".pdf"
limit=
"1"
:on-exceed=
"handleExceed"
ref=
"upload"
:on-change=
"handleFileChange"
:file-list=
"uploadFileList"
>
<el-button
class=
"sider-upload-btn"
type=
"primary"
>
<el-icon
class=
"sider-upload-btn-text"
>
<Upload
/>
</el-icon>
<span
class=
"sider-upload-btn-text"
>
上传文件
</span>
</el-button>
<template
#
tip
>
<div
class=
"sider-upload-btn-tip"
>
支持扩展名:.doc .docx .pdf
</div>
</
template
>
</el-upload>
</div>
</div>
<div
class=
"submit-area"
>
<div
class=
"tips"
>
<div
class=
"tips-icon"
>
<img
src=
"./assets/images/tips-icon.png"
alt=
""
/>
</div>
<div
class=
"tips-text"
>
内容由AI生成,无法确保真实准确,仅供参考
</div>
</div>
<div
class=
"process-footer-box"
v-if=
"isShowProcess"
>
<div
class=
"footer-left"
>
{{ isGenerating ? "报文生成中..." : "报文已生成" }}
</div>
<div
class=
"footer-right"
>
<div
class=
"icon"
></div>
<div
class=
"text"
@
click=
"handleGenerate"
>
{{ "停止" }}
</div>
</div>
</div>
<div
class=
"submit-btn"
@
click=
"getStreamChat"
v-else
>
<div
class=
"submit-icon"
>
<img
src=
"./assets/images/ai.png"
alt=
""
/>
</div>
<div
class=
"submit-text"
>
生成报文
</div>
</div>
</div>
</div>
<div
class=
"main-box"
>
<div
v-if=
"isEditMode"
class=
"edit-panel"
>
<v-md-editor
v-model=
"reportContent"
height=
"calc(100% - 40px)"
:disabled-menus=
"[]"
@
upload-image=
"handleUploadImage"
@
save=
"handleSave"
left-toolbar=
"undo redo clear | h bold italic strikethrough quote | ul ol table hr | link image code | save"
right-toolbar=
"preview toc sync-scroll fullscreen"
/>
</div>
<div
v-else
class=
"content-box"
ref=
"scrollContainer"
v-html=
"renderedContent"
></div>
</div>
</div>
</div>
</template>
<
script
setup
>
...
...
@@ -208,66 +183,62 @@ import Prism from "prismjs";
import
{
ElButton
,
ElIcon
,
ElInput
,
ElMessage
,
ElUpload
,
genFileId
}
from
"element-plus"
;
VMdEditor
.
use
(
vuepressTheme
,
{
Prism
Prism
});
const
isGenerating
=
ref
(
false
);
const
isShowProcess
=
ref
(
false
);
const
uploadFileList
=
ref
([])
const
upload
=
ref
()
const
uploadFileList
=
ref
([])
;
const
upload
=
ref
()
;
//新上传文件替换
const
handleExceed
=
(
files
)
=>
{
if
(
upload
.
value
)
{
upload
.
value
.
clearFiles
()
const
file
=
files
[
0
]
file
.
uid
=
genFileId
()
upload
.
value
.
handleStart
(
file
)
}
}
const
handleExceed
=
files
=>
{
if
(
upload
.
value
)
{
upload
.
value
.
clearFiles
();
const
file
=
files
[
0
];
file
.
uid
=
genFileId
();
upload
.
value
.
handleStart
(
file
);
}
}
;
const
handleFileChange
=
(
file
,
files
)
=>
{
// 只保留最后选中的1个文件(覆盖原有文件)
if
(
files
.
length
>
1
)
{
uploadFileList
.
value
=
[
file
];
}
else
{
uploadFileList
.
value
=
files
;
}
// 只保留最后选中的1个文件(覆盖原有文件)
if
(
files
.
length
>
1
)
{
uploadFileList
.
value
=
[
file
];
}
else
{
uploadFileList
.
value
=
files
;
}
};
const
handleBack
=
()
=>
{
handleGenerate
()
processContent
.
value
=
""
isGenerating
.
value
=
false
;
isShowProcess
.
value
=
false
;
handleGenerate
();
};
const
isEditMode
=
ref
(
false
);
const
handleSwitchMode
=
()
=>
{
isEditMode
.
value
=
!
isEditMode
.
value
;
if
(
!
isEditMode
.
value
)
{
console
.
log
(
reportContent
.
value
);
updateContent
(
reportContent
.
value
,
scrollContainer
.
value
);
}
isEditMode
.
value
=
!
isEditMode
.
value
;
if
(
!
isEditMode
.
value
)
{
console
.
log
(
reportContent
.
value
);
updateContent
(
reportContent
.
value
,
scrollContainer
.
value
);
}
};
// 保存处理函数
const
handleSave
=
(
text
,
html
)
=>
{
console
.
log
(
"保存内容:"
,
{
markdown
:
text
,
html
:
html
});
reportContent
.
value
=
text
;
// 实际保存逻辑
// saveToLocalStorage(text);
ElMessage
.
success
(
"保存成功!"
);
console
.
log
(
"保存内容:"
,
{
markdown
:
text
,
html
:
html
});
reportContent
.
value
=
text
;
// 实际保存逻辑
// saveToLocalStorage(text);
ElMessage
.
success
(
"保存成功!"
);
};
// 保存到本地存储
const
saveToLocalStorage
=
text
=>
{
localStorage
.
setItem
(
"markdown-content"
,
text
);
localStorage
.
setItem
(
"markdown-content"
,
text
);
};
const
abortController
=
ref
(
null
);
...
...
@@ -286,229 +257,230 @@ const curTempTitle = ref("法案");
// 停止生成
const
handleGenerate
=
()
=>
{
abortController
.
value
.
abort
();
isShowProcess
.
value
=
false
;
processContent
.
value
=
""
;
abortController
.
value
.
abort
();
};
// 当前调用工具
const
curAgentTool
=
ref
(
"报告整体优化工具"
);
const
getStreamChat
=
async
(
search
,
inputValue
)
=>
{
if
(
uploadFileList
.
value
.
length
>
0
)
{
const
rawFile
=
uploadFileList
.
value
[
0
].
raw
;
if
(
!
rawFile
)
{
ElMessage
.
error
(
'文件解析失败,请重新选择'
);
return
;
}
callSseWithPdf
(
rawFile
)
}
else
{
const
params
=
{
query
:
writtingTitle
.
value
,
// "输出一篇报文"
desc
:
descText
.
value
,
topic
:
curTempTitle
.
value
// 政令、智库、法案、清单
};
callSseWithAi
(
params
)
}
if
(
uploadFileList
.
value
.
length
>
0
)
{
const
rawFile
=
uploadFileList
.
value
[
0
].
raw
;
if
(
!
rawFile
)
{
ElMessage
.
error
(
"文件解析失败,请重新选择"
);
return
;
}
callSseWithPdf
(
rawFile
);
}
else
{
const
params
=
{
query
:
writtingTitle
.
value
,
// "输出一篇报文"
desc
:
descText
.
value
,
topic
:
curTempTitle
.
value
// 政令、智库、法案、清单
};
callSseWithAi
(
params
);
}
};
const
callSseWithPdf
=
async
(
selectedFile
)
=>
{
abortController
.
value
=
new
AbortController
();
try
{
// 构造FormData(和后端字段名保持一致)
const
formData
=
new
FormData
();
formData
.
append
(
'pdf'
,
selectedFile
);
// 调用fetchEventSource(核心:支持POST+FormData+SSE)
await
fetchEventSource
(
'/pdfSse/api/v1/order/pdf/extract/report/sse'
,
{
method
:
'POST'
,
// 关键:设置POST方法
body
:
formData
,
// 关键:传递PDF文件的FormData
signal
:
abortController
.
value
.
signal
,
// 中断信号
headers
:
{
// 禁用默认的SSE协议头(避免和文件上传冲突)
'Accept'
:
'text/event-stream'
,
'Cache-Control'
:
'no-cache'
,
'Connection'
:
'keep-alive'
},
// 禁用自动重连(可选,根据后端配置)
retry
:
0
,
// 核心:原生onmessage回调(无需手动分割/解析)
async
onopen
(
res
)
{
console
.
log
(
"流式回答开始"
,
res
);
isGenerating
.
value
=
true
;
isShowProcess
.
value
=
true
;
},
async
onmessage
(
res
)
{
const
{
data
,
event
}
=
res
const
jsonData
=
JSON
.
parse
(
data
)
switch
(
event
)
{
case
"progress"
:
processContent
.
value
+=
`
${
getFormattedTime
()}
:
${
jsonData
.
message
}
\r\n`
;
updateProcess
(
processContent
.
value
,
scrollProcessContainer
.
value
);
break
;
case
"result"
:
callSseWithAi
({
query
:
writtingTitle
.
value
,
// "输出一篇报文"
desc
:
descText
.
value
,
topic
:
"政令"
,
result
:
data
// 政令、智库、法案、清单
})
default
:
break
;
}
},
onerror
(
error
)
{
ElMessage
({
message
:
"写报生成报错!"
,
type
:
"warning"
});
abortController
.
value
.
abort
();
abortController
.
value
=
new
AbortController
();
throw
new
Error
(
error
);
}
});
}
catch
(
error
)
{
if
(
error
.
name
!==
'AbortError'
)
{
ElMessage
.
error
(
`请求失败:
${
error
.
message
}
`
);
isLoading
.
value
=
false
;
}
}
const
callSseWithPdf
=
async
selectedFile
=>
{
abortController
.
value
=
new
AbortController
();
try
{
// 构造FormData(和后端字段名保持一致)
const
formData
=
new
FormData
();
formData
.
append
(
"pdf"
,
selectedFile
);
// 调用fetchEventSource(核心:支持POST+FormData+SSE)
await
fetchEventSource
(
"/pdfSse/api/v1/order/pdf/extract/report/sse"
,
{
method
:
"POST"
,
// 关键:设置POST方法
body
:
formData
,
// 关键:传递PDF文件的FormData
signal
:
abortController
.
value
.
signal
,
// 中断信号
headers
:
{
// 禁用默认的SSE协议头(避免和文件上传冲突)
Accept
:
"text/event-stream"
,
"Cache-Control"
:
"no-cache"
,
Connection
:
"keep-alive"
},
openWhenHidden
:
true
,
// 核心:原生onmessage回调(无需手动分割/解析)
async
onopen
(
res
)
{
console
.
log
(
"流式回答开始"
,
res
);
isGenerating
.
value
=
true
;
isShowProcess
.
value
=
true
;
},
async
onmessage
(
res
)
{
const
{
data
,
event
}
=
res
;
const
jsonData
=
JSON
.
parse
(
data
);
switch
(
event
)
{
case
"progress"
:
processContent
.
value
+=
`
${
getFormattedTime
()}
:
${
jsonData
.
message
}
\r\n`
;
updateProcess
(
processContent
.
value
,
scrollProcessContainer
.
value
);
break
;
case
"result"
:
callSseWithAi
({
query
:
writtingTitle
.
value
,
// "输出一篇报文"
desc
:
descText
.
value
,
topic
:
"政令"
,
result
:
data
// 政令、智库、法案、清单
});
default
:
break
;
}
},
onerror
(
error
)
{
ElMessage
({
message
:
"写报生成报错!"
,
type
:
"warning"
});
abortController
.
value
.
abort
();
abortController
.
value
=
new
AbortController
();
throw
new
Error
(
error
);
}
});
}
catch
(
error
)
{
if
(
error
.
name
!==
"AbortError"
)
{
ElMessage
.
error
(
`请求失败:
${
error
.
message
}
`
);
isLoading
.
value
=
false
;
}
}
};
const
callSseWithAi
=
async
(
params
)
=>
{
abortController
.
value
=
new
AbortController
();
fetchEventSource
(
"/sseWrite/api/v1/workflow/invoke"
,
{
method
:
"POST"
,
headers
:
{
"Content-Type"
:
"application/json"
},
body
:
JSON
.
stringify
(
params
),
signal
:
abortController
.
value
.
signal
,
openWhenHidden
:
true
,
async
onopen
(
res
)
{
console
.
log
(
"流式回答开始"
,
res
);
isGenerating
.
value
=
true
;
isShowProcess
.
value
=
true
;
},
async
onmessage
(
res
)
{
let
msgData
=
JSON
.
parse
(
res
.
data
);
console
.
log
(
"resss"
,
msgData
.
data
);
console
.
log
(
"msgData"
,
msgData
);
let
str
=
msgData
.
data
;
if
(
msgData
.
event_type
===
"stream_agent_out"
)
{
if
(
str
!==
"[DONE]"
)
{
reportContent
.
value
+=
str
;
if
(
reportContent
.
value
.
includes
(
"./out/img"
))
{
reportContent
.
value
=
reportContent
.
value
.
replaceAll
(
"./out/img"
,
"http://8.140.26.4:10017/out/img"
);
// console.log(111, reportContent.value);
}
updateContent
(
reportContent
.
value
,
scrollContainer
.
value
);
}
else
{
isGenerating
.
value
=
false
;
ElMessage
.
success
(
"报文生成结束"
);
abortController
.
value
.
abort
();
abortController
.
value
=
new
AbortController
();
}
}
else
if
(
msgData
.
event_type
===
"workflow_complete"
)
{
ElMessage
.
success
(
"报文生成结束"
);
isGenerating
.
value
=
false
;
abortController
.
value
.
abort
();
abortController
.
value
=
new
AbortController
();
}
else
if
(
msgData
.
event_type
.
toLowerCase
().
includes
(
"error"
))
{
}
else
{
processContent
.
value
+=
str
;
curAgentTool
.
value
=
msgData
.
tool
;
updateProcess
(
processContent
.
value
,
scrollProcessContainer
.
value
);
}
},
onerror
(
error
)
{
ElMessage
({
message
:
"写报生成报错!"
,
type
:
"warning"
});
abortController
.
value
.
abort
();
abortController
.
value
=
new
AbortController
();
throw
new
Error
(
error
);
}
}).
catch
(
error
=>
{
ElMessage
({
message
:
"写报生成报错!"
,
type
:
"warning"
});
abortController
.
value
.
abort
();
abortController
.
value
=
new
AbortController
();
throw
new
Error
(
error
);
});
}
const
callSseWithAi
=
async
params
=>
{
abortController
.
value
=
new
AbortController
();
fetchEventSource
(
"/sseWrite/api/v1/workflow/invoke"
,
{
method
:
"POST"
,
headers
:
{
"Content-Type"
:
"application/json"
},
body
:
JSON
.
stringify
(
params
),
signal
:
abortController
.
value
.
signal
,
openWhenHidden
:
true
,
async
onopen
(
res
)
{
console
.
log
(
"流式回答开始"
,
res
);
isGenerating
.
value
=
true
;
isShowProcess
.
value
=
true
;
},
async
onmessage
(
res
)
{
let
msgData
=
JSON
.
parse
(
res
.
data
);
console
.
log
(
"resss"
,
msgData
.
data
);
console
.
log
(
"msgData"
,
msgData
);
let
str
=
msgData
.
data
;
if
(
msgData
.
event_type
===
"stream_agent_out"
)
{
if
(
str
!==
"[DONE]"
)
{
reportContent
.
value
+=
str
;
if
(
reportContent
.
value
.
includes
(
"./out/img"
))
{
reportContent
.
value
=
reportContent
.
value
.
replaceAll
(
"./out/img"
,
"http://8.140.26.4:10017/out/img"
);
// console.log(111, reportContent.value);
}
updateContent
(
reportContent
.
value
,
scrollContainer
.
value
);
}
else
{
isGenerating
.
value
=
false
;
ElMessage
.
success
(
"报文生成结束"
);
abortController
.
value
.
abort
();
abortController
.
value
=
new
AbortController
();
}
}
else
if
(
msgData
.
event_type
===
"workflow_complete"
)
{
ElMessage
.
success
(
"报文生成结束"
);
isGenerating
.
value
=
false
;
abortController
.
value
.
abort
();
abortController
.
value
=
new
AbortController
();
}
else
if
(
msgData
.
event_type
.
toLowerCase
().
includes
(
"error"
))
{
}
else
{
processContent
.
value
+=
str
;
curAgentTool
.
value
=
msgData
.
tool
;
updateProcess
(
processContent
.
value
,
scrollProcessContainer
.
value
);
}
},
onerror
(
error
)
{
ElMessage
({
message
:
"写报生成报错!"
,
type
:
"warning"
});
abortController
.
value
.
abort
();
abortController
.
value
=
new
AbortController
();
throw
new
Error
(
error
);
}
}).
catch
(
error
=>
{
ElMessage
({
message
:
"写报生成报错!"
,
type
:
"warning"
});
abortController
.
value
.
abort
();
abortController
.
value
=
new
AbortController
();
throw
new
Error
(
error
);
});
}
;
const
getFormattedTime
=
()
=>
{
const
now
=
new
Date
();
// 补零函数:确保单个数字补为两位(如 1 → 01,9 → 09)
const
pad
=
n
=>
n
.
toString
().
padStart
(
2
,
'0'
);
const
now
=
new
Date
();
// 补零函数:确保单个数字补为两位(如 1 → 01,9 → 09)
const
pad
=
n
=>
n
.
toString
().
padStart
(
2
,
"0"
);
return
`
${
now
.
getFullYear
()}
-
${
pad
(
now
.
getMonth
()
+
1
)}
-
${
pad
(
now
.
getDate
())}
${
pad
(
now
.
getHours
())}
:
${
pad
(
now
.
getMinutes
())}
:
${
pad
(
now
.
getSeconds
())}
`
;
return
`
${
now
.
getFullYear
()}
-
${
pad
(
now
.
getMonth
()
+
1
)}
-
${
pad
(
now
.
getDate
())}
${
pad
(
now
.
getHours
())}
:
${
pad
(
now
.
getMinutes
()
)}
:
${
pad
(
now
.
getSeconds
())}
`
;
};
const
writtingTitle
=
ref
(
""
);
const
descText
=
ref
(
""
);
const
tabList
=
ref
([
{
name
:
"写报"
,
active
:
true
},
{
name
:
"收藏"
,
active
:
false
},
{
name
:
"问答"
,
active
:
false
}
{
name
:
"写报"
,
active
:
true
},
{
name
:
"收藏"
,
active
:
false
},
{
name
:
"问答"
,
active
:
false
}
]);
const
tempList
=
ref
([
{
title
:
"法案1"
,
desc
:
"基于法案内容生成各维度的综合分析报告"
},
{
title
:
"智库"
,
desc
:
"基于智库内容生成各维度的综合分析报告"
},
{
title
:
"政令"
,
desc
:
"基于政令内容生成各维度的综合分析报告"
},
{
title
:
"清单"
,
desc
:
"基于清单内容生成各维度的综合分析报告"
}
{
title
:
"法案1"
,
desc
:
"基于法案内容生成各维度的综合分析报告"
},
{
title
:
"智库"
,
desc
:
"基于智库内容生成各维度的综合分析报告"
},
{
title
:
"政令"
,
desc
:
"基于政令内容生成各维度的综合分析报告"
},
{
title
:
"清单"
,
desc
:
"基于清单内容生成各维度的综合分析报告"
}
]);
const
tempActiveIndex
=
ref
(
0
);
const
handleClickTemp
=
(
item
,
index
)
=>
{
tempActiveIndex
.
value
=
index
;
curTempTitle
.
value
=
item
.
title
;
tempActiveIndex
.
value
=
index
;
curTempTitle
.
value
=
item
.
title
;
};
// 导出
const
exportContent
=
()
=>
{
const
blob
=
new
Blob
([
reportContent
.
value
],
{
type
:
"text/markdown"
});
const
url
=
URL
.
createObjectURL
(
blob
);
const
a
=
document
.
createElement
(
"a"
);
a
.
href
=
url
;
a
.
download
=
`markdown-
${
new
Date
().
getTime
()}
.md`
;
a
.
click
();
URL
.
revokeObjectURL
(
url
);
const
blob
=
new
Blob
([
reportContent
.
value
],
{
type
:
"text/markdown"
});
const
url
=
URL
.
createObjectURL
(
blob
);
const
a
=
document
.
createElement
(
"a"
);
a
.
href
=
url
;
a
.
download
=
`markdown-
${
new
Date
().
getTime
()}
.md`
;
a
.
click
();
URL
.
revokeObjectURL
(
url
);
};
onMounted
(()
=>
{
});
onMounted
(()
=>
{});
onUnmounted
(()
=>
{
if
(
abortController
.
value
)
{
abortController
.
value
.
abort
();
}
if
(
abortController
.
value
)
{
abortController
.
value
.
abort
();
}
});
</
script
>
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论