提交 5e26754e authored 作者: 朱亚刚's avatar 朱亚刚

pdf写报(未完成)

上级 08966e42
......@@ -31,39 +31,24 @@
</div>
<div class="writting-main">
<div class="sider">
<div class="sider-box1">
<div class="sider-box" v-if="false">
<div class="header">报文主题</div>
<div class="title-box">
<div class="title">主题名称</div>
<el-input
style="width: 476px; height: 32px"
class="title-input"
placeholder="输入主题名称,如:大而美法案"
v-model="writtingTitle"
/>
<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
class="description-input"
type="textarea"
style="width: 476px"
:rows="8"
placeholder="输入报文主题描述,如:从科技领域方面分析大而美法案通过后对中国可能产生的影响"
v-model="descText"
/>
<el-input :disabled="true" class="description-input" type="textarea" style="width: 476px"
:rows="8" placeholder="输入报文主题描述,如:从科技领域方面分析大而美法案通过后对中国可能产生的影响" v-model="descText" />
</div>
</div>
<div class="sider-box2">
<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="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">
......@@ -79,14 +64,32 @@
</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 class="submit-btn" @click="getStreamChat">
<div class="tips">
<div class="tips-icon">
<img src="./assets/images/tips-icon.png" alt="" />
</div>
<div class="tips-text">内容由AI生成,无法确保真实准确,仅供参考</div>
</div>
</div>
<div class="submit-btn" @click="getStreamChat">
<div class="submit-icon">
<img src="./assets/images/ai.png" alt="" />
</div>
......@@ -95,10 +98,9 @@
</div>
<div class="process-box" v-if="isShowProcess">
<div class="back" @click="handleBack">
{{ "< 返回" }}
</div>
<div class="process-main-box">
<!-- <div class="analysis-box">
{{ "< 返回" }} </div>
<div class="process-main-box">
<!-- <div class="analysis-box">
<div class="analysis-header">
<div class="icon">
<img src="./assets/images/right-arrow.png" alt="" />
......@@ -111,55 +113,50 @@
}}
</div>
</div> -->
<div class="steps-box">
<div class="steps-header">
<div class="icon">
<img src="./assets/images/right-arrow.png" alt="" />
<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="text">{{ "执行步骤:" }}</div>
</div>
<div class="steps-content" ref="scrollProcessContainer" v-html="renderedProcess"></div>
</div>
<!-- <div class="doing-box">
<!-- <div class="doing-box">
{{ "正在执行步骤1/7:根据制图主题生成关键词" }}
</div> -->
<div class="tool-box">
<div class="tool-header">{{ "工具调用" }}</div>
<div class="tool-main">当前智能体工具:{{ curAgentTool ? curAgentTool : "无" }}</div>
</div>
</div>
<div class="process-tips-box">
<div class="tips-icon">
<img src="./assets/images/tips-icon.png" alt="" />
</div>
<div class="tips-text">内容由AI生成,无法确保真实准确,仅供参考</div>
<div class="tool-box">
<div class="tool-header">{{ "工具调用" }}</div>
<div class="tool-main">当前智能体工具:{{ curAgentTool ? curAgentTool : "无" }}</div>
</div>
</div>
<div class="process-tips-box">
<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">
<div class="footer-left">
{{ isGenerating ? "报文生成中..." : "报文已生成" }}
</div>
<div class="footer-right">
<div class="icon"></div>
<div class="text" @click="handleGenerate">{{ "停止" }}</div>
</div>
</div>
</div>
<div class="process-footer-box">
<div class="footer-left">
{{ isGenerating ? "报文生成中..." : "报文已生成" }}
</div>
<div class="footer-right">
<div class="icon"></div>
<div class="text" @click="handleGenerate">{{ "停止" }}</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 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>
......@@ -175,6 +172,7 @@ import "@kangc/v-md-editor/lib/theme/style/vuepress.css";
// 引入 Prism 相关依赖
import Prism from "prismjs";
import { ElButton, ElIcon, ElInput, ElMessage, ElUpload, genFileId } from "element-plus";
VMdEditor.use(vuepressTheme, {
Prism
......@@ -182,6 +180,28 @@ VMdEditor.use(vuepressTheme, {
const isGenerating = ref(false);
const isShowProcess = ref(false);
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 handleFileChange = (file, files) => {
// 只保留最后选中的1个文件(覆盖原有文件)
if (files.length > 1) {
uploadFileList.value = [file];
} else {
uploadFileList.value = files;
}
};
const handleBack = () => {
isShowProcess.value = false;
......@@ -219,7 +239,6 @@ const steps = [
];
const isEditMode = ref(false);
const handleSwitchMode = () => {
isEditMode.value = !isEditMode.value;
if (!isEditMode.value) {
......@@ -269,59 +288,77 @@ const handleGenerate = () => {
const curAgentTool = ref("报告整体优化工具");
const getStreamChat = async (search, inputValue) => {
const params = {
query: writtingTitle.value, // "输出一篇报文"
desc: descText.value,
topic: curTempTitle.value // 政令、智库、法案、清单
};
if (uploadFileList.value.length > 0) {
const rawFile = uploadFileList.value[0].raw;
if (!rawFile) {
ElMessage.error('文件解析失败,请重新选择');
return;
}
callSseApi(rawFile)
} else {
abortController.value = new AbortController();
const params = {
query: writtingTitle.value, // "输出一篇报文"
desc: descText.value,
topic: curTempTitle.value // 政令、智库、法案、清单
};
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);
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();
}
updateContent(reportContent.value, scrollContainer.value);
} else {
isGenerating.value = false;
} 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);
}
} else if (msgData.event_type === "workflow_complete") {
ElMessage.success("报文生成结束");
isGenerating.value = false;
},
onerror(error) {
ElMessage({
message: "写报生成报错!",
type: "warning"
});
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);
throw new Error(error);
}
},
onerror(error) {
}).catch(error => {
ElMessage({
message: "写报生成报错!",
type: "warning"
......@@ -329,18 +366,205 @@ const getStreamChat = async (search, inputValue) => {
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 callSseApi = async (selectedFile) => {
abortController.value = new AbortController();
try {
const formData = new FormData();
formData.append('pdf', selectedFile);
const response = await fetch('/pdfSse/api/v1/order/pdf/extract/report/sse', {
method: 'POST',
body: formData,
signal: abortController.value.signal, // 绑定中断信号
});
if (!response.ok) {
throw new Error(`请求失败:${response.status} ${response.statusText}`);
}
console.log("流式回答开始", res);
isGenerating.value = true;
isShowProcess.value = true;
// 读取流式响应
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = ''; // 消息缓冲区
// 定义SSE消息回调(和原生onmessage用法一致)
const onmessage = (res) => {
const { type, data } = res
if (type === "progress") {
processContent.value += data.message;
updateProcess(processContent.value, scrollProcessContainer.value);
}
};
// 错误回调
const onerror = (error) => {
};
// 连接关闭回调
const onclose = () => {
};
// 循环读取并解析SSE消息(核心修复换行符兼容)
while (true) {
try {
const { done, value } = await reader.read();
// 连接正常关闭
if (done) {
onclose();
break;
}
// 1. 解码二进制流为文本,追加到缓冲区
buffer += decoder.decode(value, { stream: true });
// 2. 分割完整消息(兼容 \r\n\r\n 和 \n\n 换行符)
const fullMessages = buffer.split(/(\r\n|\n){2}/);
// 过滤空字符串,只保留有效消息
const validMessages = fullMessages.filter(msg => msg.trim() !== '');
// 3. 最后一条可能是不完整消息,放回缓冲区
let remainingBuffer = '';
if (validMessages.length > 0) {
remainingBuffer = validMessages.pop() || '';
}
// 4. 逐条解析有效消息
validMessages.forEach(fullMsg => {
const sseMsg = parseSSEMessage(fullMsg);
// 过滤心跳/注释消息(以:开头的消息)
if (sseMsg.isComment) return;
// 触发onmessage回调
if (sseMsg.data) {
debugger
onmessage({
type: sseMsg.event || 'message',
data: JSON.parse(sseMsg.data), // 解析为JSON对象
timeStamp: Date.now()
});
}
});
// 重置缓冲区(只保留不完整的消息)
buffer = remainingBuffer;
} catch (error) {
// 排除主动中断的情况
if (error.name !== 'AbortError') {
onerror(error);
}
break;
}
}
} catch (error) {
// 捕获请求级别的错误
if (error.name !== 'AbortError') {
ElMessage.error(`请求异常:${error.message}`);
isLoading.value = false;
}
}
};
// 工具函数:严格按SSE协议解析单条消息
const parseSSEMessage = (rawMsg) => {
// 兼容 \r\n 和 \n 分割行
const lines = rawMsg.split(/\r\n|\n/);
const result = {
event: 'progress', // 默认事件类型
data: '', // 消息数据
isComment: false // 是否是注释/心跳消息
};
lines.forEach(line => {
line = line.trimEnd(); // 去掉行尾空白符
// 注释行(以:开头):心跳消息,标记为注释
if (line.startsWith(':')) {
result.isComment = true;
return;
}
// 解析event行(event: xxx)
if (line.startsWith('event:')) {
result.event = line.slice(6).trim();
return;
}
// 解析data行(data: xxx),支持多行data拼接
if (line.startsWith('data:')) {
result.data += line.slice(5).trim();
return;
}
// 空行忽略
if (line === '') return;
});
return result;
};
const ele = () => {
return new Promise((resolve, reject) => {
// 转换FormData为Blob(适配SSE的POST请求体)
const formDataBlob = new Blob([
// 模拟multipart/form-data的边界符(简化版,实际可复用浏览器自动生成的)
...Array.from(formData.entries()).map(([key, value]) => {
return `--boundary\r\nContent-Disposition: form-data; name="${key}"${value instanceof File ? `; filename="${value.name}"\r\nContent-Type: ${value.type}` : ''}\r\n\r\n${value instanceof File ? value : value}\r\n`;
}),
'--boundary--\r\n'
]);
fetchEventSource('/pdfSse/api/v1/order/pdf/extract/report/sse', {
method: 'POST',
headers: {
// 关键:设置multipart/form-data头,包含边界符
'Content-Type': `multipart/form-data; boundary=boundary`,
},
// 注意:fetchEventSource的body仅支持字符串/ArrayBuffer/Blob,这里传FormData转换后的Blob
body: formDataBlob,
signal: abortController.value.signal,
openWhenHidden: true,
// SSE连接开启
async onopen(res) {
console.log("流式回答开始", res);
isGenerating.value = true;
isShowProcess.value = true;
},
async onmessage(res) {
debugger
const { event, data } = res
let jsonData = JSON.parse(data);
if (event === "progress") {
processContent.value += jsonData.message;
updateProcess(processContent.value, scrollProcessContainer.value);
}
},
onerror(error) {
ElMessage({
message: "写报生成报错!",
type: "warning"
});
abortController.value.abort();
abortController.value = new AbortController();
throw new Error(error);
}
}).catch((error) => {
reject(error);
isProcessing.value = false;
});
});
}
const writtingTitle = ref("");
const descText = ref("");
const tabList = ref([
......@@ -381,7 +605,7 @@ const tempActiveIndex = ref(0);
const handleClickTemp = (item, index) => {
tempActiveIndex.value = index;
curTempTitle.value = item.title;
};
// 导出
......@@ -395,7 +619,7 @@ const exportContent = () => {
URL.revokeObjectURL(url);
};
onMounted(() => {});
onMounted(() => { });
onUnmounted(() => {
if (abortController.value) {
......@@ -408,6 +632,7 @@ onUnmounted(() => {
.writting-wrapper {
width: 100%;
height: 100%;
.writting-header {
height: 60px;
box-sizing: border-box;
......@@ -417,6 +642,7 @@ onUnmounted(() => {
background: rgba(255, 255, 255, 1);
display: flex;
position: relative;
.tab-box {
display: flex;
margin-left: 130px;
......@@ -424,6 +650,7 @@ onUnmounted(() => {
width: 260px;
height: 46px;
justify-content: space-between;
.tab {
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
......@@ -431,6 +658,7 @@ onUnmounted(() => {
font-weight: 400;
line-height: 30px;
}
.tabActive {
color: rgba(5, 95, 194, 1);
font-family: Microsoft YaHei;
......@@ -440,12 +668,14 @@ onUnmounted(() => {
border-bottom: 4px solid rgba(5, 95, 194, 1);
}
}
.btn-box {
position: absolute;
top: 12px;
right: 39px;
display: flex;
gap: 12px;
.btn {
display: flex;
justify-content: center;
......@@ -458,14 +688,17 @@ onUnmounted(() => {
border-radius: 6px;
background: rgba(255, 255, 255, 1);
cursor: pointer;
.icon {
width: 16px;
height: 16px;
img {
width: 100%;
height: 100%;
}
}
.text {
width: 32px;
height: 24px;
......@@ -475,19 +708,23 @@ onUnmounted(() => {
font-weight: 400;
line-height: 24px;
}
.text1 {
color: #fff;
}
}
.btn1 {
background: rgba(5, 95, 194, 1);
}
}
}
.writting-main {
display: flex;
height: calc(100% - 60px);
position: relative;
.process-box {
position: absolute;
left: 0;
......@@ -496,6 +733,7 @@ onUnmounted(() => {
height: 100%;
z-index: 9999;
background: #fff;
.back {
margin-top: 21px;
height: 24px;
......@@ -508,24 +746,29 @@ onUnmounted(() => {
line-height: 24px;
cursor: pointer;
}
.process-main-box {
margin-top: 20px;
margin-left: 22px;
width: 476px;
height: 900px;
// background: orange;
.analysis-box {
.analysis-header {
display: flex;
.icon {
margin-top: 5px;
width: 20px;
height: 20px;
img {
width: 100%;
height: 100%;
}
}
.text {
height: 30px;
line-height: 30px;
......@@ -536,6 +779,7 @@ onUnmounted(() => {
margin-left: 5px;
}
}
.analysis-content {
height: 90px;
line-height: 30px;
......@@ -546,19 +790,24 @@ onUnmounted(() => {
text-indent: 32px;
}
}
.steps-box {
margin-top: 20px;
.steps-header {
display: flex;
.icon {
margin-top: 5px;
width: 20px;
height: 20px;
img {
width: 100%;
height: 100%;
}
}
.text {
height: 30px;
line-height: 30px;
......@@ -569,6 +818,7 @@ onUnmounted(() => {
margin-left: 5px;
}
}
.steps-content {
height: 560px;
width: 100%;
......@@ -597,6 +847,7 @@ onUnmounted(() => {
// }
}
}
.doing-box {
height: 40px;
line-height: 40px;
......@@ -606,18 +857,21 @@ onUnmounted(() => {
font-weight: 400;
margin-left: 20px;
}
.tool-box {
width: 440px;
height: 160px;
margin: 10px auto;
background: #f6f9fe;
border-radius: 10px;
.tool-header {
height: 30px;
line-height: 30px;
margin-left: 20px;
color: var(--color-main-active);
}
.tool-main {
height: 110px;
width: 400px;
......@@ -631,21 +885,25 @@ onUnmounted(() => {
}
}
}
.process-tips-box {
position: absolute;
left: 22px;
bottom: 81px;
height: 22px;
display: flex;
.tips-icon {
width: 14px;
height: 16px;
margin-top: 3px;
img {
width: 100%;
height: 100%;
}
}
.tips-text {
margin-left: 8px;
color: rgba(132, 136, 142, 1);
......@@ -655,12 +913,14 @@ onUnmounted(() => {
line-height: 22px;
}
}
.process-footer-box {
height: 36px;
display: flex;
position: absolute;
left: 22px;
bottom: 29px;
.footer-left {
width: 348px;
height: 36px;
......@@ -673,6 +933,7 @@ onUnmounted(() => {
text-align: center;
line-height: 36px;
}
.footer-right {
margin-left: 8px;
display: flex;
......@@ -686,12 +947,14 @@ onUnmounted(() => {
align-items: center;
gap: 8px;
cursor: pointer;
.icon {
width: 8px;
height: 8px;
border-radius: 2px;
background: var(--color-main-active);
}
.text {
color: var(--color-main-active);
font-family: Microsoft YaHei;
......@@ -702,6 +965,7 @@ onUnmounted(() => {
}
}
}
.sider {
width: 520px;
box-sizing: border-box;
......@@ -709,62 +973,28 @@ onUnmounted(() => {
border-top: 1px solid rgba(234, 236, 238, 1);
background: rgba(255, 255, 255, 1);
position: relative;
.sider-box1 {
margin-top: 21px;
margin-left: 22px;
.header {
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 700;
line-height: 24px;
}
.title-box {
margin-top: 15px;
.title {
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
}
.title-input {
margin-top: 15px;
}
}
.description-box {
margin-top: 24px;
.title {
height: 24px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
}
.description-input {
margin-top: 12px;
height: 200px;
}
}
}
.sider-box2 {
margin-top: 24px;
margin-left: 22px;
padding: 21px 21px;
display: flex;
flex-direction: column;
gap: 23px;
.sider-box {
.header {
height: 24px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 700;
line-height: 24px;
}
.template-box {
margin-top: 19px;
height: 260px;
display: flex;
flex-wrap: wrap;
gap: 16px;
.template {
width: 230px;
height: 120px;
......@@ -773,6 +1003,7 @@ onUnmounted(() => {
border-radius: 4px;
position: relative;
cursor: pointer;
.active-icon {
width: 24px;
height: 24px;
......@@ -780,11 +1011,13 @@ onUnmounted(() => {
top: 0;
right: 0;
z-index: 99;
img {
width: 100%;
height: 100%;
}
}
.selected-icon {
width: 8px;
height: 6px;
......@@ -792,15 +1025,18 @@ onUnmounted(() => {
top: -4px;
right: 3px;
z-index: 100;
img {
width: 8px;
height: 6px;
}
}
.header {
display: flex;
justify-content: space-between;
height: 50px;
.title {
height: 24px;
// color: rgba(59, 65, 75, 1);
......@@ -812,6 +1048,7 @@ onUnmounted(() => {
margin-left: 15px;
margin-top: 16px;
}
.icon {
margin-top: 15px;
margin-right: 16px;
......@@ -819,6 +1056,7 @@ onUnmounted(() => {
height: 30px;
border-radius: 15px;
background: rgba(231, 243, 255, 1);
img {
width: 17px;
height: 14px;
......@@ -827,6 +1065,7 @@ onUnmounted(() => {
}
}
}
.content {
margin: 0 auto;
width: 200px;
......@@ -839,24 +1078,117 @@ onUnmounted(() => {
line-height: 24px;
}
}
.tempActive {
border: 1px solid rgba(5, 95, 194, 1);
background: rgba(246, 250, 255, 1);
}
}
.tips {
.title-box {
margin-top: 15px;
.title {
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
}
.title-input {
margin-top: 15px;
}
}
.description-box {
margin-top: 24px;
.title {
height: 24px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
}
.description-input {
margin-top: 12px;
height: 200px;
}
}
.sider-upload-btn {
width: 476px;
height: 36px;
box-sizing: border-box;
border: 1px dashed rgba(234, 236, 238, 1);
border-radius: 6px;
background: rgba(247, 248, 249, 1);
margin-top: 19px;
}
.sider-upload-btn-text {
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 14px;
font-weight: 400;
line-height: 22px;
letter-spacing: 0px;
text-align: left;
}
.sider-upload-btn-tip {
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 14px;
font-weight: 400;
line-height: 22px;
letter-spacing: 0px;
text-align: left;
margin-top: 8px;
}
}
.submit-btn {
position: absolute;
left: 22px;
bottom: 13px;
width: 476px;
height: 36px;
border-radius: 4px;
background: rgba(5, 95, 194, 1);
display: flex;
justify-content: center;
cursor: pointer;
&:hover {
background: rgba(5, 95, 194, 0.8);
}
.tips {
height: 22px;
display: flex;
position: absolute;
top: -30px;
left: 0px;
.tips-icon {
width: 14px;
height: 16px;
margin-top: 3px;
img {
width: 100%;
height: 100%;
}
}
.tips-text {
margin-left: 8px;
color: rgba(132, 136, 142, 1);
......@@ -866,31 +1198,19 @@ onUnmounted(() => {
line-height: 22px;
}
}
}
.submit-btn {
position: absolute;
left: 22px;
bottom: 13px;
width: 476px;
height: 36px;
border-radius: 4px;
background: rgba(5, 95, 194, 1);
display: flex;
justify-content: center;
cursor: pointer;
&:hover {
background: rgba(5, 95, 194, 0.8);
}
.submit-icon {
/* AI-logo */
width: 21px;
height: 15px;
margin-top: 10px;
img {
width: 100%;
height: 100%;
}
}
.submit-text {
height: 24px;
margin-top: 5px;
......@@ -903,14 +1223,17 @@ onUnmounted(() => {
}
}
}
.main-box {
flex: 1;
background: #f7f8f9;
.edit-panel {
width: calc(100% - 100px);
height: calc(100% - 40px);
margin: 20px 50px;
}
.content-box {
width: calc(100% - 100px);
height: calc(100% - 40px);
......@@ -924,7 +1247,8 @@ onUnmounted(() => {
line-height: 1.7;
// font-size: 20px;
font-size: 16px;
img{
img {
width: 300px;
height: auto;
}
......
......@@ -80,6 +80,17 @@ export default defineConfig({
target: 'http://8.140.26.4:15000/',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/temporarySearch/, '')
},
'/pdfSse': {
target: 'http://8.140.26.4:10020/',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/pdfSse/, ''),
configure: (proxy) => {
proxy.on('proxyReq', (proxyReq) => {
proxyReq.setHeader('Connection', 'keep-alive');
proxyReq.setHeader('Cache-Control', 'no-cache');
});
}
}
}
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论