This commit is contained in:
2025-07-29 15:18:31 +08:00
parent bd8dd6db3c
commit 544af2a4d2
5 changed files with 585 additions and 166 deletions

View File

@@ -14,7 +14,8 @@
"
:visible.sync="dialogVisible"
:close-on-click-modal="false"
:wrapperClosable="false"
:wrapperClosable="true"
:before-close="handleClose"
custom-class="yianDrawer"
size="1200px"
>
@@ -60,23 +61,34 @@
<div
v-for="(v, i) in messageList"
class="wordItem"
@click="insertMessage(v)"
@click="insertMessage(v.text, v.images ? v.images : [])"
style="width: 32%;margin-right: 15px;margin-bottom: 10px;cursor: pointer;"
>
<div
style="border: 1px solid #bbb;border-radius: 8px;height: 88px;overflow: hidden;"
style="border: 1px solid #bbb;border-radius: 8px;height: 110px;overflow: hidden;"
>
<p
style="font-weight: bold;margin-bottom:2px;margin-top: -1px;background-color: #f0f0f0;color: #333;padding: 2px 10px 2px 2px;"
>
医案 {{ numberToChineseLower(i + 1) }}
<el-button
@click.stop="
analyzingMessage(v.text, v.images ? v.images : [])
"
size="mini"
type=""
plain
style="margin-left: 10px; padding: 2px;float: right;color: rgb(23, 129, 255);"
>解析医案</el-button
>
<el-button
@click.stop="insertMessage(v.text, v.images ? v.images : [])"
size="mini"
type=""
plain
icon="el-icon-plus"
style="margin-left: 10px; padding: 2px;float: right;"
>快速填入</el-button
>选择</el-button
>
</p>
<div
@@ -89,7 +101,16 @@
text-overflow: ellipsis;
word-break: break-word; /* 可选:精确限制高度,兼容性更好 */"
>
{{ v }}
{{ v.text }}
</div>
<div v-if="v.images" style="padding:0px 10px 0;">
<img
v-for="(img, i) in v.images"
:key="i"
:src="img"
style="width:30px;height: 30px; margin: 4px;"
/>
</div>
</div>
</div>
@@ -157,7 +178,7 @@
v-if="tishi"
:title="
loading
? '解析预计耗时约50秒,请耐心等待'
? '解析预计耗时约50秒,请耐心等待,也可在草稿箱中查看内容'
: '好的结合您的医案下面是解析后的结果。5秒后自动关闭'
"
:type="loading ? 'warning' : 'success'"
@@ -243,7 +264,10 @@
>
</div>
<template
v-if="type == 'detail' && currentNode.data.id == 'wait'"
v-if="
(type == 'detail' && currentNode.data.id == 'wait') ||
currentNode.data.id == 'caogao'
"
style="display:flex;align-items:center;justify-content:space-between"
>
<!-- <el-form-item
@@ -273,7 +297,6 @@
<div>
<el-cascader
size="mini"
:disabled="isEdit"
style="width: 100%;"
:show-all-levels="false"
v-model="addCertificateForm.labelId"
@@ -281,7 +304,9 @@
value: 'id',
label: 'title'
}"
filterable
:options="cateOptions"
@change="selectLabelId"
placeholder="医案分类"
></el-cascader></div
></el-form-item>
@@ -330,7 +355,6 @@
<el-form-item
label="医案详情:"
label-width="110px"
class="form_item"
>
<div style="padding-top: 15px;">
@@ -377,7 +401,6 @@
<el-form-item
label="上传图片:"
label-width="110px"
class="form_item custom-upload-box"
v-if="dialogVisible"
@@ -438,23 +461,20 @@
</div>
</div>
</el-upload>
<template v-if="addCertificateForm.img !== ''&&type == 'detail'">
<el-image
v-if="
fileList.length > 0
"
:key="index"
class="el-upload-list__item-thumbnail"
v-for="(item, index) in addCertificateForm.img.split(',')"
style="width: 60px;height: 60px;border-radius: 6px;margin: 0 8px 8px 0;"
:src="item"
:preview-src-list="addCertificateForm.img.split(',')"
<template
v-if="addCertificateForm.img !== '' && type == 'detail'"
>
</el-image>
<el-image
v-if="fileList.length > 0"
:key="index"
class="el-upload-list__item-thumbnail"
v-for="(item, index) in addCertificateForm.img.split(',')"
style="width: 60px;height: 60px;border-radius: 6px;margin: 0 8px 8px 0;"
:src="item"
:preview-src-list="addCertificateForm.img.split(',')"
>
</el-image>
</template>
<!-- <div class="flexBox" style="width:100%;justify-content: space-between;">
<div class="" style="display:flex">
@@ -613,10 +633,13 @@ export default {
data() {
return {
isShowWord: false,
imagePreviews: false,
record: {},
loading: false,
tishi: false,
message: "",
currentMedicalWordImageList: [],
currentMedicalWordImageStr: "",
messageList: [],
showMessages: false,
editableMap: {}, // 存储每个字段的内部可编辑内容
@@ -684,6 +707,7 @@ export default {
addForm: {},
audioFileList: [],
isFresh: false,
pollInterval: null,
type: "",
detailContent: "",
medicalId: "",
@@ -698,6 +722,7 @@ export default {
commonShopTable,
quillEditor
},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
@@ -712,6 +737,30 @@ export default {
// this.getDataList();
},
methods: {
selectLabelId(value) {
// value 是选中的 id 数组
const getTitle = (options, valuePath) => {
let currentOptions = options;
let labels = [];
for (let val of valuePath) {
const selected = currentOptions.find(item => item.id === val);
if (selected) {
labels.push(selected.title);
currentOptions = selected.children || [];
} else {
break;
}
}
return labels;
};
// 获取选中的 title 路径
const titles = getTitle(this.cateOptions, value);
console.log("当前选中的 title 是:", titles[titles.length - 1]); // 如果只要最后一级
this.addCertificateForm.labelTitle = titles[titles.length - 1];
},
numberToChineseLower(n) {
const cnNums = [
"零",
@@ -743,10 +792,20 @@ export default {
result = result.replace(/^一十/, "十"); // 10-19 处理为 十一、十二...
return result;
},
insertMessage(data) {
insertMessage(data, images) {
this.message = "";
this.currentMedicalWordImageList = [];
this.currentMedicalWordImageStr = "";
this.message = data;
if (images.length > 0) {
this.currentMedicalWordImageList = [...images];
}
console.log("this.message at line 650:", this.message);
},
async analyzingMessage(data, images) {
await this.insertMessage(data, images);
await this.submit()
},
// 点击按钮触发上传
triggerUpload() {
this.messageList = [];
@@ -756,19 +815,22 @@ export default {
// 处理上传文件
handleUpload(event) {
const loading = this.$loading({
lock: true,
text: 'word文件识别中',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
this.$commonJS.handleUpload(event, arr => {
console.log("content at line 618:", arr);
// const text = html
// .replace(/<[^>]+>/g, '') // 清除所有 HTML 标签
// .replace(/&nbsp;/g, ' ') // 替换空格实体
// .replace(/&lt;/g, '<') // 还原小于号
// .replace(/&gt;/g, '>') // 还原大于号
// .replace(/&amp;/g, '&') // 还原 &
// .replace(/\r?\n\s*\r?\n/g, '\n') // 去掉多余空行
this.messageList = arr;
// document.getElementById("result").innerHTML = content
loading.close();
}).catch(()=>{
loading.close();
});
},
beforeClose() {
@@ -887,6 +949,8 @@ export default {
init(type, data) {
this.showMessages = false;
this.messageList = [];
this.currentMedicalWordImageList = [];
this.currentMedicalWordImageStr = "";
this.message = "";
this.tishi = false;
this.loading = false;
@@ -900,10 +964,11 @@ export default {
chiefComplaint: "<h1>主诉</h1>",
historyOfPresentIllness: "<h1>现病史</h1>",
pastHistory: "<h1>既往史</h1>",
personalAndFamilyHistory: "<h1>家族史</h1>",
personalAndFamilyHistory: "<h1>个人史与家族史</h1>",
physicaExamination: "<h1>体格检查</h1>",
diagnosis: "<h1>诊断</h1>",
treatmentPlan: "<h1>治疗和后续治疗</h1>"
treatmentPlan: "<h1>治疗和后续治疗</h1>",
treatmentPlan: "<h1>其他</h1>"
};
this.isEdit = type == "edit" || type == "add" ? true : false;
if (type == "add") {
@@ -1047,35 +1112,96 @@ export default {
this.reviewType = type;
this.dialogMarkVisible = true;
},
async uploadImage(base64Images) {
const uploadTasks = base64Images.map((base64, index) => {
const formData = new FormData();
const blob = this.$commonJS.base64ToBlob(base64);
formData.append("file", blob, `image-${index + 1}.png`);
submit() {
return fetch(this.baseUrl + "/oss/fileoss", {
method: "POST",
body: formData
})
.then(res => res.json())
.then(data => {
console.log(`✅ 第 ${index + 1} 张上传完成`, data);
if (data.code === 0 && data.url) {
return data.url;
} else {
console.warn(`❌ 第 ${index + 1} 张上传失败`);
return null;
}
})
.catch(err => {
console.error(`❌ 第 ${index + 1} 张上传失败`, err);
return null;
});
});
// 🚀 等待所有任务并发完成
const results = await Promise.all(uploadTasks);
const urlList = results.filter(Boolean); // 去掉失败的 null
const urlString = urlList.join(",");
console.log("✅ 所有上传完成URL 字符串:", urlString);
return urlString;
},
async submit() {
//没有次数的时候要求购买vip
if (!this.message) {
this.$message.error("请输入医案详情");
return;
}
this.createChat()
if (this.currentMedicalWordImageList.length > 0) {
const loading = this.$loading({
lock: true,
text: 'loading',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
this.currentMedicalWordImageStr = await this.uploadImage(
this.currentMedicalWordImageList
);
console.log(
"this.currentMedicalWordImageStr at line 1139:",
this.currentMedicalWordImageStr
);
loading.close();
}
await this.createChat();
//创建对话 获取sessionId
},
//创建新对话
createChat() {
this.loading = true;
this.$http({
url: this.$http.adornUrl("/common/medicalRecords/medicalRecordsSplit"),
method: "post",
data: this.$http.adornData({
userId: "1",
message: this.message
userId: "12301",
message: this.message,
img: this.currentMedicalWordImageStr
})
}).then(res => {
console.log("res at line 872:", res);
if (res.data.code == 0) {
this.medicalId = res.data.data;
})
.then(res => {
console.log("res at line 872:", res);
if (res.data.code == 0) {
this.medicalId = res.data.data;
this.sendQuestion();
}
});
this.sendQuestion();
} else {
this.loading = false;
this.$message.error("请重新解析");
}
})
.catch(() => {
this.loading = false;
this.$message.error("请重新解析");
});
},
//交谈请求,获取回答
@@ -1085,7 +1211,6 @@ export default {
this.showMessages = true;
this.loading = true;
var that = this;
//展示提示语
this.tishi = true;
@@ -1094,14 +1219,15 @@ export default {
const poll = () => {
this.getMedicalDetail(() => {
// 停止轮询
clearInterval(pollInterval);
clearInterval(this.pollInterval);
this.pollInterval = null;
setTimeout(() => {
this.tishi = false;
}, 5000);
});
};
// 每5秒发送一次请求直到收到正确的响应
const pollInterval = setInterval(poll, 5000);
this.pollInterval = setInterval(poll, 5000);
//调用后端 SSE 接口,发送问题并接收实时回答
// this.startSSE(params);
@@ -1119,6 +1245,18 @@ export default {
})
.then(res => {
if (
res.data.code == 0 &&
res.data.medicalRecords != null &&
res.data.medicalRecords.delFlag == -1
) {
this.$message.error("此医案解析失败,请重新解析");
this.showMessages = true;
if (fn) {
fn();
}
return false;
}
if (
res.data.code == 0 &&
res.data.medicalRecords != null &&
@@ -1163,6 +1301,22 @@ export default {
// this.$refs.commonMedicalDetail.initRecordData(this.medicalRecords);
// that.initRecordData();
console.log("at line 558:", this.record);
this.addCertificateForm.id = data.id;
this.addCertificateForm.img = data.img;
if (this.addCertificateForm.img) {
this.fileList = this.addCertificateForm.img
.split(",")
.map((image, i) => ({
uid: i, // 假设 id 是唯一标识符
name: i, // 文件名
status: "done", // 状态
url: image // 文件 URL
}));
console.log("this.fileList at line 308:", this.fileList);
this.addCertificateForm.imageList = this.addCertificateForm.img.split(
","
);
}
this.$forceUpdate();
// 滚动到最底部锚点
@@ -1192,6 +1346,7 @@ export default {
this.$message.error("请选择用户");
return false;
}
if (this.editableMap.chiefComplaint == "") {
const titleHtml = this.getTitleHtml(
this.record["chiefComplaint"]
@@ -1220,6 +1375,49 @@ export default {
this.$message.error("请输入 " + titleHtml);
return false;
}
if (
["妇科", "儿科"].includes(this.currentNode.data.title) ||
["妇科", "儿科"].includes(this.addCertificateForm.labelTitle)
) {
if (
this.currentNode.data.title == "妇科" ||
this.addCertificateForm.labelTitle == "妇科"
) {
const value = this.editableMap["personalAndFamilyHistory"] || "";
const hasKeywords =
value.includes("月经") && value.includes("婚育");
if (!hasKeywords) {
// 包含“月经”或“婚育”
console.log("包含月经或婚育相关内容");
const titleHtml = this.getTitleHtml(
this.record["personalAndFamilyHistory"]
).replace(/<[^>]*>/g, "");
this.$message.error(
"请在 " + titleHtml + " 中输入月经或婚育相关内容"
);
return false;
}
}
if (
this.currentNode.data.title == "儿科" ||
this.addCertificateForm.labelTitle == "儿科"
) {
const value = this.editableMap["pastHistory"] || "";
const hasKeywords = value.includes("疫苗");
if (!hasKeywords) {
// 包含“月经”或“婚育”
console.log("疫苗");
const titleHtml = this.getTitleHtml(
this.record["pastHistory"]
).replace(/<[^>]*>/g, "");
this.$message.error(
"请在 " + titleHtml + " 中输入疫苗接种相关内容"
);
return false;
}
}
}
var recordData = { ...this.record };
for (const key in recordData) {
const titleHtml = this.getTitleHtml(recordData[key]);
@@ -1234,29 +1432,52 @@ export default {
userId: this.addCertificateForm.userId,
...recordData
};
if (this.currentNode.data.id == "caogao") {
const label = this.addCertificateForm.labelId;
console.log(
"this.addCertificateForm at line 1286:",
this.addCertificateForm
);
const value = Array.isArray(label)
? label[label.length - 1]
: label;
console.log("value at line 1289:", value);
if (!value) {
this.$message.error("请选择医案分类");
return false;
}
data = {
...this.addCertificateForm,
...data,
labelId: value,
state: 3
};
console.log("data at line 1288:", data);
} else {
if (this.type == "edit") {
data = {
...data,
data: this.addCertificateForm.data
? this.addCertificateForm.data
: "",
id: this.addCertificateForm.id
};
} else {
data = {
...data,
labelId: this.labelId
};
}
}
// if(this.record.)
this.$http({
url: this.$http.adornUrl(
this.type == "edit"
this.type == "edit" || this.currentNode.data.id == "caogao"
? "/master/medicalRecords/editMedicalRecords"
: "/master/medicalRecords/addMedicalRecords"
),
method: "post",
data: this.$http.adornData(
this.type == "edit"
? {
...data,
data: this.addCertificateForm.data
? this.addCertificateForm.data
: "",
id: this.addCertificateForm.id
}
: {
...data,
labelId: this.labelId
}
)
data: this.$http.adornData({ ...data })
}).then(({ data }) => {
if (data && data.code === 0) {
this.$message({
@@ -1315,7 +1536,14 @@ export default {
},
handlePictureCardPreview(file) {
// 图片预览逻辑
},
handleClose(done) {
done();
this.$emit("refresh");
}
},
beforeDestroy() {
clearInterval(this.pollInterval);
}
};
</script>