Files
taimed/pages/medicalRecords/add copy.vue
2025-07-24 17:21:45 +08:00

1942 lines
41 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="content">
<z-nav-bar title="新增医案" bgColor="#5188e5" fontColor="#fff"> </z-nav-bar>
<view class="home_wrap home_wrap_analysis" v-if="!showMessages">
<view class="home_form" style="position: relative">
<view
class="form_item"
style="
display: flex;
align-items: flex-start;
justify-content: space-between;
"
>
<!-- <text>医案信息</text> -->
<!-- 固定标题和输入框部分 -->
<view class="analysis_box">
<view class="analysis_title">
<image
src="../../static/icon/icon_analysis.png"
style="
width: 50rpx;
height: 50rpx;
margin-right: 10rpx;
margin-top: 10rpx;
"
></image>
智能分析医案
</view>
<!-- 固定的输入框部分 -->
<view style="height: calc(100% - 80rpx)">
<textarea
v-model="formData.message"
maxlength="-1"
style="min-height: calc(88vh - 100px) !important; width: 100%; max-height: calc(88vh - 100px) !important;"
auto-height
placeholder="请输入医案到此处,将自动解析医案信息
例:
基本信息太湖65岁
首诊2023-04-26
主诉:发现...."
placeholder-class="custom-placeholder"
></textarea>
</view>
</view>
<view class="submit_btn" @click="submit">解析医案</view>
</view>
</view>
<!-- 搜索结果列表 -->
<scroll-view
scroll-y
class="result-list"
v-if="searchResultStatus && searchResults.length > 0"
>
<view
v-for="item in searchResults"
:key="item.id"
@click="selectItem(item)"
class="result-item"
>
{{ item.name }}
</view>
</scroll-view>
</view>
<view class="message_wrap" :style="{ top: 1 + 'px' }" v-if="showMessages">
<text class="message_title" v-if="tishi"
>好的结合您的医案下面是解析后的结果</text
>
<!-- 显示聊天记录 -->
<scroll-view
scroll-y
:style="{ height: '100%' }"
:scroll-into-view="scrollIntoView"
scroll-with-animation
>
<view class="message-container-block">
<view class="loading-spinner" v-if="loading"></view>
<view class="home_wrap" style="margin: 0" v-if="!loading">
<view class="home_form" style="margin-top: 40rpx">
<view class="form_item">
<text>医案标题</text>
<textarea
auto-height
v-model="formData.title"
maxlength="-1"
placeholder="请输入医案标题"
placeholder-class="custom-placeholder"
/>
</view>
<view
class="form_item"
style="
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 14px;
"
>
<text>医案详情</text>
<view style="width: calc(100% - 200rpx)">
<view
class=""
v-for="(html, key) in record"
:key="key"
style="
padding: 4rpx;
margin-bottom: 20rpx;
box-sizing: border-box;
"
>
<!-- 显示字段标题 -->
<view
class="h1_box"
v-html="`${getTitleHtml(html, key)}`"
style="
margin-top: 0;
margin-bottom: 10px;
font-weight: bold;
display: flex;
align-items: center;
"
></view>
<view class="editor-wrapper">
<editor
placeholder=""
style="color: black"
:value="editableMap[key]"
@input="(e) => editorInput(e, key)"
@ready="onEditorReady(key)"
:id="`editorId${key}`"
></editor>
</view>
<!-- <view
class="detail_info_medical"
v-else
v-html="editableMap[key]"
></view> -->
</view>
</view>
</view>
<view class="form_item">
<text>医案分类</text>
<view
style=""
@click="showDrawer"
class="form_item_customize"
:style="
formData.labelId
? 'color:#5188e5;font-weight: 700;'
: 'color:#888'
"
>{{
formData.labelId ? formData.labelTitle : "请选择医案分类"
}}</view
>
</view>
<view
class="form_item"
style="
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 14px;
"
>
<text>上传图片</text>
<view class="in" style="border: none" @click="checkPermision">
<u-upload
:fileList="fileList1"
@afterRead="addPic"
@delete="deletePic"
multiple
width="50"
height="50"
:previewFullImage="true"
>
</u-upload>
</view>
</view>
</view>
<!-- 搜索结果列表 -->
<scroll-view
scroll-y
class="result-list"
v-if="searchResultStatus && searchResults.length > 0"
>
<view
v-for="item in searchResults"
:key="item.id"
@click="selectItem(item)"
class="result-item"
>
{{ item.name }}
</view>
</scroll-view>
</view>
</view>
<view id="bottom-anchor"></view>
</scroll-view>
<!-- <view class="aiFlag">本回答由AI生成内容仅供参考</view> -->
<!-- <view class="submit_form submit_form_2">
<view class="assistants_list">
<textarea auto-height v-model="question_send" placeholder="给智慧医疗发送消息"
placeholder-class="custom-placeholder" />
</view>
<button class="submit_btn" @click="sendAgain">
<image src='../../static/icon/icon_submit.png' v-if="!pauseStatus"></image>
<image src='../../static/icon/icon_submit_pause.png' v-if="pauseStatus"></image>
</button>
</view> -->
<view class="footer_box" v-if="!loading">
<view class="footer_item">
<view class="button savebutton" @click="handleSubmit('save')"
>暂存草稿箱</view
>
</view>
<view class="footer_item"
><view class="button" @click="handleSubmit('submit')"
>提交审核</view
></view
>
</view>
</view>
<tree-list
ref="treeList"
v-if="treeListVisible"
@clickCourseInfo="clickCourseInfo"
></tree-list>
<!-- <z-navigation></z-navigation> -->
</view>
</template>
<script>
import $http from "@/config/requestConfig.js";
import { mapState, mapMutations } from "vuex";
import treeList from "./tag.vue";
import qs from "qs";
export default {
components: {
treeList,
},
data() {
return {
editorOptions: {
theme: "snow", // Quill 编辑器的主题
modules: {
toolbar: [["bold", "italic"], ["link"]],
},
},
fileList1: [],
treeListVisible: false,
containerHeight: null,
formData: {
diagnosis: "",
illness: "",
symptoms: "",
result: "",
genetic: "",
name: "",
},
chatId: null, //选择助手的id
chatName: "",
chatAssistants: [],
activeIndex: null,
sessionId: "5fe38e6b-8816-4668-879c-99910b5e431b", //对话id
eventSource: null,
showMessages: false,
loading: true,
question: "", //传递的问题
messages: [],
record: [],
previousAnswer: null, //存储上一条回答内容
question_send: "",
pauseStatus: false, //暂停操作
record_list: [], //对话列表
null_text: "",
activeRecord: null,
tishi: false, //提示语
folderList: [], //病历夹列表
folderName: "", //病历夹名称
chatAssistantName: "",
patientName: "",
pageData: {},
pageType: "", //从患者列表过来的type
isChecked: true,
selectedItems: [], //模糊已选项
selectedId: [],
searchResults: [], //模糊搜索结果
searchResultStatus: false,
vipCount: null,
vipText: "",
vipStatus: null,
freeCount: null,
freeText: "",
freeStatus: null,
flag: null,
scrollIntoView: "",
recordData: {
information: "<h1>1. 一般信息</h1>",
chiefComplaint: "<h1>2. 主诉</h1>",
historyOfPresentIllness: "<h1>3. 现病史</h1>",
pastHistory: "<h1>4. 既往史</h1>",
personalAndFamilyHistory: "<h1>5. 家族史</h1>",
physicaExamination: "<h1>6. 体格检查</h1>",
diagnosis: "<h1>7. 诊断</h1>",
treatmentPlan: "<h1>8. 治疗和后续治疗</h1>",
},
editableMap: {},
};
},
computed: {
...mapState(["userInfo"]),
},
onLoad() {
uni.hideTabBar();
uni.removeStorageSync("homeParams");
//获取设备信息
const systemInfo = uni.getSystemInfoSync();
this.containerHeight = systemInfo.windowHeight; //获取设备的窗口高度
// this.sendQuestion();
},
onShow() {
// console.log('进入到onShow方法')
// this.activeRecord = null;
// this.getRecordsData();
// this.getUserAiVipCount(); //更新次数
// //我的-会话记录跳转来的
// this.pageData = uni.getStorageSync('homeParams').data;
// this.pageType = uni.getStorageSync('homeParams').type;
// let index = uni.getStorageSync('homeParams').index;
// if(this.pageData&&!this.pageType){
// this.clickRecord(this.pageData, index);
// }
},
methods: {
handleSubmit(type) {
if(type=='submit'){
if(!this.formData.title){
this.$commonJS.showToast("请输入医案标题");
return
}
if (this.editableMap.chiefComplaint == "") {
const titleHtml = this.getTitleHtml(
this.record["chiefComplaint"]
).replace(/<[^>]*>/g, "");
this.$commonJS.showToast("请输入 " + titleHtml);
return false;
}
if (this.editableMap.historyOfPresentIllness == "") {
const titleHtml = this.getTitleHtml(
this.record["historyOfPresentIllness"]
).replace(/<[^>]*>/g, "");
this.$commonJS.showToast("请输入 " + titleHtml);
return false;
}
if (this.editableMap.physicaExamination == "") {
const titleHtml = this.getTitleHtml(
this.record["physicaExamination"]
).replace(/<[^>]*>/g, "");
this.$commonJS.showToast("请输入 " + titleHtml);
return false;
}
if (this.editableMap.treatmentPlan == "") {
const titleHtml = this.getTitleHtml(
this.record["treatmentPlan"]
).replace(/<[^>]*>/g, "");
this.$commonJS.showToast("请输入 " + titleHtml);
return false;
}
}
var recordData = { ...this.record };
for (const key in recordData) {
const titleHtml = this.getTitleHtml(recordData[key]);
recordData[key] = titleHtml + this.editableMap[key];
}
var data = {
img:
this.fileList1.length > 0
? this.fileList1.map((e) => e.url).toString()
: "",
title: this.formData.title,
state: type == "submit" ? 1 : 0,
...recordData,
};
this.$http
.request({
url: "common/medicalRecords/saveMedicalRecords",
method: "POST",
data: {
...data,
},
header: {
"Content-Type": "application/json",
},
})
.then((res) => {
if (res.code == 0) {
console.log("res.code at line 434:", res.code);
}
});
},
onStatusChange(e) {
this.formats = e.detail;
},
editorInput(e, key) {
console.log("key at line 292:", e, key);
},
onEditorReady(key) {
this.$nextTick(() => {
// 在 DOM 更新后执行 createSelectorQuery
uni
.createSelectorQuery()
.in(this)
.select(`#editorId${key}`)
.context((res) => {
console.log("res at line 303:", res); // 输出调试信息
if (!res || !res.context) return; // 如果没有找到 context直接返回
// 获取编辑器内容,判断是否为空内容或无效内容
let content = this.editableMap[key] || "";
// 判断是否为空或无效内容
if (this.isEmptyContent(content)) {
content = ""; // 如果内容无效,清空编辑器内容
} else {
// 替换所有的 HTML 实体,如 &quot; => "
content = this.replaceHtmlEntities(content);
}
if (content) {
// 如果内容有效,设置编辑器内容
res.context.setContents({
html: content,
});
} else {
// 如果没有有效内容,可以选择清空编辑器
console.log("No valid content to set in the editor.");
}
})
.exec();
});
},
// 判断内容是否为空或无效
isEmptyContent(content) {
// 检查是否为空字符串或仅包含空白字符
return !content.trim() || content === '""';
},
// 替换 HTML 实体字符
replaceHtmlEntities(content) {
// 替换常见的 HTML 实体
return content
.replace(/&quot;/g, '"') // 替换 &quot; 为 "
.replace(/&lt;/g, "<") // 替换 &lt; 为 <
.replace(/&gt;/g, ">") // 替换 &gt; 为 >
.replace(/&amp;/g, "&") // 替换 &amp; 为 &
.replace(/&nbsp;/g, " "); // 替换 &nbsp; 为 空格
},
getInnerHtml(html) {
const div = document.createElement("div");
div.innerHTML = html;
const children = Array.from(div.children).slice(1); // 跳过 h1
return children.map((e) => e.outerHTML).join("");
},
getTitleHtml(html, key) {
const div = document.createElement("div");
div.innerHTML = html;
var str = [
"chiefComplaint",
"historyOfPresentIllness",
"physicaExamination",
"treatmentPlan",
].includes(key)
? `<span style="color:#F56C6C;margin-right:4px">*</span>`
: "";
return div.querySelector("h1")
? div.querySelector("h1").outerHTML || "<h1></h1>"
: "";
},
async checkPermision() {
var result = await permission.premissionCheck("CAMERA_EXTERNAL_STORAGE");
if (result != 1) {
return false;
}
},
async addPic(e) {
let that = this;
for (var i = 0; i < e.file.length; i++) {
uni.uploadFile({
url: this.$baseUrl + "/oss/fileoss",
filePath: e.file[i].url,
name: "file",
formData: {},
success: (res) => {
that.fileList1.push({
url: JSON.parse(res.data).url,
});
},
fail: (error) => {},
});
}
},
deletePic(event) {
this.fileList1.splice(event.index, 1);
},
clickCourseInfo(val) {
console.log(val);
this.formData.labelId = val.id;
this.formData.labelTitle = val.title;
this.$forceUpdate();
},
showDrawer() {
this.treeListVisible = true;
this.$nextTick(() => {
this.$refs["treeList"].getData();
});
},
//设置滚动到最底部
scrollToBottom() {
this.scrollIntoView = "";
setTimeout(() => {
this.scrollIntoView = "bottom-anchor";
}, 50);
},
//基因
handleInput(val) {
let name = val.detail.value;
this.getGenes(name);
},
//模糊搜索选中
selectItem(item) {
if (!this.selectedItems.some((i) => i.id === item.id)) {
this.selectedItems.push(item.name);
this.selectedId.push(item.id);
}
this.formData.genetic = "";
this.searchResultStatus = false;
console.log(this.selectedItems);
console.log(this.selectedId);
},
//删除标签
removeTag(index) {
this.selectedItems.splice(index, 1);
this.selectedId.splice(index, 1);
console.log(this.selectedItems);
console.log(this.selectedId);
},
//基因模糊查询列表
getGenes(name) {
this.$http
.request({
url: "taihumed/precisionMedicine/getPrecisionMedicineGenes",
method: "POST",
data: { name: name },
header: {
"Content-Type": "application/json",
},
})
.then((res) => {
if (res.code == 0) {
if (res.genes && res.genes.length > 0) {
this.searchResults = res.genes;
this.searchResultStatus = true;
} else {
this.searchResults = "";
this.searchResultStatus = false;
}
}
});
},
//勾选
toggleCheck() {
this.isChecked = !this.isChecked;
},
//获取病症种类数据
//获取对话记录数据
getRecordsData() {
this.record_list = [];
this.$http
.request({
url: "common/ragFlowApi/getChats",
method: "POST",
data: {
chatId: "",
sessionId: "",
page: 1,
pageSize: 300,
},
header: {
"Content-Type": "application/json",
},
})
.then((res) => {
if (res.code == 0) {
console.log("请求最新列表");
if (res.list && res.list.length > 0) {
this.record_list = res.list;
//患者列表跳转来的
const index = res.list.findIndex(
(item) =>
item.chatAssistantId === this.pageData.chatAssistantId &&
item.chatId === this.pageData.chatId
);
if (this.pageType && this.pageType == "patient") {
this.clickRecord(this.pageData, index);
}
} else {
this.record_list = [];
this.null_text = "暂无数据";
}
}
})
.catch((e) => {
console.log(e);
});
},
//请求问答剩余次数
getUserAiVipCount() {
this.$http
.request({
url: "taihumed/aiVip/getUserAiVip",
method: "POST",
data: {},
header: {
"Content-Type": "application/json",
},
})
.then((res) => {
if (res.code == 0) {
this.flag = res.flag; //0-免费次数1-可升级
if (res.aiVipLog && res.aiVipLog.surplusCount >= 0) {
this.vipCount = res.aiVipLog.surplusCount;
this.vipText = "问答剩余:";
this.vipStatus = true;
}
if (res.freeCount >= 0) {
this.freeStatus = true;
this.freeCount = res.freeCount;
this.freeText = "赠送[全科医生]免费问答:";
} else {
this.freeStatus = false;
this.freeCount = null;
}
}
})
.catch((e) => {
uni.setStorageSync("guidePages", 2);
});
},
//点击每个记录
clickRecord(item, index) {
//重新定义id
this.chatId = item.chatAssistantId;
this.sessionId = item.chatId;
//助手类型
this.chatName = item.chatAssistantName;
this.patientName = item.patientName;
console.log("我是:" + this.patientName);
uni.setStorageSync("homeParams", { data: item, index: index });
this.activeRecord = index;
this.messages = [];
this.showMessages = true;
//请求病历夹接口
this.getRecordFolderList();
//如果正在回答的时候切换需要中断回答
this.closeWebSocket();
uni.showLoading({
title: "加载中",
});
this.$http
.request({
url: "common/ragFlowApi/getChats",
method: "POST",
data: {
chatId: item.chatAssistantId,
sessionId: item.chatId,
page: 1,
pageSize: 300,
},
header: {
"Content-Type": "application/json",
},
})
.then((res) => {
if (res.code == 0) {
uni.hideLoading();
if (res.list && res.list.length > 0) {
this.messages = res.list.map((item) => {
let content = item.content.replace(/##\d+$$/g, "");
content = item.content.replace(/<\/?think>/g, "");
content = content.replace(
/\*\*(.*?)\*\*/g,
'<b class="bold-text">$1</b>'
);
content = content.replace(
/\*(.*?)\*/g,
'<span class="red-text">$1</span>'
);
content = content.replace(/\n\n/g, "\n");
content = content.replace(/\n/g, "<br>");
//content = content.replace(/^#{3,4}.*(\r?\n)?/gm, '');
return {
...item,
type: item.type === 1 ? "answer" : "question",
content: content,
};
});
//滚动到最底部锚点
this.$nextTick(() => {
this.scrollToBottom();
});
}
this.tishi = false; //提示语不用展示
this.$refs.drawer.close();
}
});
},
//选中科目类别
clickAssistants(item, index) {
this.activeIndex = index;
this.chatId = item.id;
this.chatName = item.name;
},
//提交
submit() {
let content = "";
let confirmText = "确定";
//没有次数的时候要求购买vip
if (!this.formData.message) {
this.$commonJS.showToast("请输入医案详情");
return;
}
//创建对话 获取sessionId
this.createChat();
},
//创建新对话
createChat() {
this.$http
.request({
url: "common/medicalRecords/medicalRecordsSplit",
method: "POST",
data: {
message: this.formData.message,
},
header: {
"Content-Type": "application/json",
},
})
.then((res) => {
if (res.code == 0) {
this.sessionId = res.data;
this.sendQuestion();
}
});
},
initRecordData(data) {
this.record = {
information: data.information
? data.information
: recordData.information,
chiefComplaint: data.chiefComplaint
? data.chiefComplaint
: recordData.chiefComplaint,
historyOfPresentIllness: data.historyOfPresentIllness
? data.historyOfPresentIllness
: recordData.historyOfPresentIllness,
pastHistory: data.pastHistory
? data.pastHistory
: recordData.pastHistory,
personalAndFamilyHistory: data.personalAndFamilyHistory
? data.personalAndFamilyHistory
: recordData.personalAndFamilyHistory,
physicaExamination: data.physicaExamination
? data.physicaExamination
: recordData.physicaExamination,
diagnosis: data.diagnosis ? data.diagnosis : recordData.diagnosis,
treatmentPlan: data.treatmentPlan
? data.treatmentPlan
: recordData.treatmentPlan,
};
for (const key in this.record) {
this.$set(this.editableMap, key, this.getInnerHtml(this.record[key]));
}
},
//交谈请求,获取回答
sendQuestion() {
//清空消息记录
this.messages = [];
this.showMessages = true;
this.pauseStatus = true;
this.loading = true;
var that = this;
//展示提示语
this.tishi = true;
const poll = () => {
this.$http
.request({
url: "common/medicalRecords/medicalRecordsQuerySplit",
method: "POST",
data: {
queryFlag: this.sessionId,
},
header: {
"Content-Type": "application/json",
},
})
.then((res) => {
if (res.code == 0 && res.medicalRecords != null) {
console.log(res, "999999");
that.pauseStatus = false;
that.loading = false;
that.initRecordData(res.medicalRecords);
console.log("at line 558:", that.record);
that.$forceUpdate();
// 滚动到最底部锚点
// that.$nextTick(() => {
// that.scrollToBottom();
// });
// 停止轮询
clearInterval(pollInterval);
}
})
.catch((error) => {
console.log("请求出错:", error);
});
};
// 每5秒发送一次请求直到收到正确的响应
const pollInterval = setInterval(poll, 5000);
//调用后端 SSE 接口,发送问题并接收实时回答
// this.startSSE(params);
},
//开始监听 SSE 数据
startSSE(params) {
const queryString = qs.stringify(params);
var data = {};
this.eventSource = uni.connectSocket({
url: this.$baseUrl + `websocket`,
success: () => {
console.log("WebSocket连接中...");
$http
.request({
url: `common/ragFlowApi/chatToAssistantStream?${queryString}`,
method: "GET",
data,
header: {
"Content-Type": "application/json",
},
})
.then((res) => {
console.log("请求成功");
})
.catch((e) => {
console.log("失败");
});
},
fail: (err) => {
console.error("连接失败", err);
uni.showToast({ title: "连接失败", icon: "error" });
},
});
// 监听服务器发送的消息
uni.onSocketMessage((event) => {
try {
const message = JSON.parse(event.data);
if (message.data === true) {
console.log("回答已结束");
this.pauseStatus = false;
this.loading = false;
//获取最近的会话记录数据
this.getRecordsData();
setTimeout(() => {
this.closeWebSocket();
}, 200);
return;
}
const answer = message.data.answer.replace(/##\d+$$/g, "");
console.log(message.data.answer);
let newAnswer = ""; //初始化 newAnswer 变量
if (this.previousAnswer === null) {
console.log("第一次进来");
//如果没有包含上一条的内容,则直接显示当前 answer
newAnswer = answer;
this.messages.push({ content: newAnswer, type: "answer" });
this.previousAnswer = newAnswer;
} else {
//只显示新增的部分
newAnswer = answer.replace(this.previousAnswer, "");
newAnswer = newAnswer.replace(
/\*\*(.*?)\*\*/g,
'<b class="bold-text">$1</b>'
);
newAnswer = newAnswer.replace(
/\*(.*?)\*/g,
'<span class="red-text">$1</span>'
);
newAnswer = newAnswer.replace(/\n\n/g, "\n");
newAnswer = newAnswer.replace(/\n/g, "<br>");
newAnswer = newAnswer
.replace(/####([\s\S]*?)$/gm, "<h4>$1</h4>")
.replace(/###([\s\S]*?)$/gm, "<h3>$1</h3>");
this.messages.push({ content: newAnswer, type: "answer" });
this.previousAnswer = answer;
}
//滚动到最底部锚点
this.$nextTick(() => {
this.scrollToBottom();
});
} catch (error) {
this.loading = false;
this.closeWebSocket();
}
});
//监听WebSocket连接打开
uni.onSocketOpen(() => {
console.log("WebSocket已连接");
});
//监听WebSocket错误
uni.onSocketError((err) => {
console.error("WebSocket连接错误", err);
});
//监听WebSocket关闭
uni.onSocketClose((res) => {
console.log("WebSocket 已关闭", res);
});
},
//回答界面的提交
sendAgain() {
console.log("这是再一次提问");
if (!this.pauseStatus) {
if (!this.question_send) {
this.$commonJS.showToast("请输入发送内容");
return;
}
const params = {
chatId: this.chatId,
chatName: this.chatName,
question: this.question_send,
sessionId: this.sessionId,
sessionName: this.question_send.slice(0, 15),
patientName: this.formData.name,
};
this.messages.push({
content: `${this.question_send}`,
type: "question",
});
//滚动到最底部锚点
this.$nextTick(() => {
this.scrollToBottom();
});
this.loading = true;
this.question_send = "";
this.pauseStatus = true;
this.previousAnswer = null;
//调用后端 SSE 接口,发送问题并接收实时回答
this.startSSE(params);
} else {
console.log("不能点击了");
}
},
//点击左侧弹窗
openDrawer() {
this.$refs.drawer.open();
},
//点击新会话
showMode() {
this.showMessages = false;
this.messages = [];
this.formData = {
diagnosis: "",
illness: "",
symptoms: "",
genetic: "",
name: "",
};
this.chatId = null;
this.activeIndex = null;
this.activeRecord = null;
this.patientName = "";
this.selectedItems = [];
this.searchResultStatus = false;
//中断
this.closeWebSocket();
this.previousAnswer = null;
this.pauseStatus = false;
//把缓存清除
uni.removeStorageSync("homeParams");
//剩余次数
this.getUserAiVipCount();
},
//问答界面点击创建病历夹
clickFolder() {
if (this.pauseStatus) {
this.$commonJS.showToast("正在回答中,请稍候");
return;
}
if (this.folderList.length == 0) {
uni.showModal({
title: "提示",
content: "您还没有病历夹,确定创建新的病历夹吗?",
confirmText: "确定",
cancelText: "取消",
success: (res) => {
if (res.confirm) {
this.$refs.add_folder.open("center");
} else if (res.cancel) {
console.log("取消创建病历夹");
}
},
});
} else {
this.$refs.popup.open("center");
}
},
//获取病历夹列表
getRecordFolderList() {
this.$http
.request({
url: "taihumed/aiRecordFolder/getRecordFolders",
method: "POST",
data: {
assistantId: this.chatId,
chatId: this.sessionId,
folderName: "",
patientName: "",
},
header: {
"Content-Type": "application/json",
},
})
.then((res) => {
if (res.code == 0) {
if (res.list && res.list.length > 0) {
this.folderList = res.list;
}
}
})
.catch((e) => {
console.log(e);
});
},
//点击创建病历夹
createFolder() {
this.$refs.popup.close();
this.$refs.add_folder.open();
this.folderName = "";
this.isChecked = true;
},
//创建病历夹
addRecordFolder() {
if (!this.folderName) {
this.$commonJS.showToast("请输入病历夹名称");
return;
}
if (!this.isChecked) {
uni.showLoading({
title: "正在创建中",
});
}
this.$http
.request({
url: "taihumed/aiRecordFolder/addRecordFolder",
method: "POST",
data: {
folderName: this.folderName,
sort: 0,
},
header: {
"Content-Type": "application/json",
},
})
.then((res) => {
if (res.code == 0) {
uni.hideLoading();
//如果把当前对话放入病历夹
if (this.isChecked) {
let id = res.aiRecordFolder.id;
this.addRecordFolderChat(id);
} else {
uni.showToast({
title: "创建成功",
icon: "success",
});
this.$refs.add_folder.close();
this.getRecordFolderList(); //刷新列表数据
}
}
});
},
//询问是否加入
askJoin(data) {
if (data.here == 1) {
this.$commonJS.showToast("不可重复加入病历夹");
return;
}
this.$refs.popup.close();
uni.showModal({
title: "提示",
content: "确定加入[" + data.folderName + "]病历夹吗?",
confirmText: "确定",
cancelText: "取消",
success: (res) => {
if (res.confirm) {
this.addRecordFolderChat(data.id, "0");
} else if (res.cancel) {
console.log("取消加入病历夹");
}
},
});
},
//对话记录加入病历夹
addRecordFolderChat(id, type) {
let text1 = "";
let text2 = "";
let patientName = "";
if (type == "0") {
text1 = "正在加入该病历夹";
text2 = "加入成功";
} else {
text1 = "正在创建中";
text2 = "创建成功";
}
uni.showLoading({
title: text1,
});
//患者名字
if (this.formData.name) {
patientName = this.formData.name;
} else {
patientName = this.patientName;
}
this.$http
.request({
url: "taihumed/aiRecordFolder/addRecordFolderChat",
method: "POST",
data: {
folderId: id,
patientName: patientName,
chatAssistantId: this.chatId,
chatId: this.sessionId,
},
header: {
"Content-Type": "application/json",
},
})
.then((res) => {
uni.hideLoading();
uni.showToast({
title: text2,
icon: "success",
});
this.$refs.add_folder.close();
this.$refs.popup.close();
this.getRecordFolderList(); //刷新列表数据
});
},
//关闭进程和监听
closeWebSocket() {
if (this.eventSource) {
// 关闭连接并移除监听
this.eventSource.close({
success: () => {
console.log("WebSocket 已关闭-closeWebSocket");
uni.offSocketMessage(); //移除消息监听
},
});
this.eventSource = null;
this.loading = false;
this.pauseStatus = false;
}
},
},
onHide() {
this.closeWebSocket();
},
onUnload() {
this.closeWebSocket();
},
};
</script>
<style lang="scss" scoped>
@import "@/static/mixin.scss";
.content {
background: linear-gradient(to bottom, #d8e6ff 0%, #d8e6ff57 90%, #fff 98%);
}
.home_top {
width: 100%;
background: #fff;
position: fixed;
top: 0;
left: 0;
padding: 90rpx 50rpx 30rpx;
text-align: center;
box-sizing: border-box;
z-index: 999;
.home_top_icon {
position: absolute;
left: 40rpx;
top: 85rpx;
display: flex;
align-items: center;
.home_top_left,
.home_top_right {
width: 60rpx;
height: 60rpx;
padding: 10rpx;
box-sizing: border-box;
}
.home_top_right {
margin-left: 30rpx;
}
}
text {
font-size: 43rpx;
line-height: 44rpx;
font-weight: bold;
color: $themeColor;
}
.home_top_folder {
padding: 12rpx;
position: absolute;
right: 40rpx;
top: 75rpx;
image {
width: 50rpx;
height: 50rpx;
}
}
}
.home_wrap {
margin: 0rpx 30rpx 0;
// padding-bottom: 300rpx;
overflow: hidden;
.home_logo {
padding-top: 40rpx;
image {
display: block;
width: 130rpx;
height: 130rpx;
margin: 0 auto;
}
.logo_main {
text-align: center;
display: block;
padding-top: 30rpx;
font-size: 35rpx;
color: $themeColor;
line-height: 46rpx;
}
.logo_con {
display: block;
width: 510rpx;
margin: 30rpx auto;
font-size: 28rpx;
color: #303030;
line-height: 40rpx;
text-indent: 2em;
}
}
}
.home_form {
margin-top: 60rpx;
padding-bottom: 80rpx;
position: relative;
.form_item {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 30rpx;
text {
line-height: 68rpx;
font-size: 30rpx;
color: #fff;
background: $themeBgColor;
text-align: center;
border-radius: 20rpx;
padding: 0 25rpx;
border: 1rpx solid $themeBgColor;
box-sizing: border-box;
}
textarea,
input,
.form_item_customize {
display: inline-block;
width: calc(100% - 200rpx);
height: 70rpx;
line-height: 35rpx;
padding: 17rpx 30rpx;
font-size: 28rpx;
color: #303030;
border-radius: 50rpx;
border: 1rpx solid #777778;
box-sizing: border-box;
resize: none;
max-height: 200rpx;
overflow-y: scroll;
}
}
}
.custom-placeholder {
font-size: 28rpx;
color: #8b8c90 !important;
}
.submit_form {
width: 100%;
height: 90px;
background: #fff;
position: fixed;
left: 0;
bottom: 120rpx;
padding: 0 50rpx;
z-index: 999;
}
.submit_form_2 {
height: 135rpx;
padding: 30rpx;
.assistants_list {
textarea,
input {
width: calc(100% - 65px);
font-size: 26rpx;
line-height: 34rpx;
border-radius: 50rpx;
padding: 22rpx 30rpx;
color: #303030;
background: #f3f4f6;
max-height: 72rpx;
overflow: hidden;
}
}
.submit_btn {
top: 42rpx;
}
}
.assistants_list {
display: flex;
align-items: center;
flex-wrap: wrap;
.assistants_item {
display: flex;
align-items: center;
width: 217rpx;
margin-top: 30rpx;
image {
width: 38rpx;
height: 38rpx;
}
text {
padding-left: 10rpx;
display: inline-block;
font-size: 28rpx;
color: #606061;
}
.assistants_img_1 {
display: block;
}
.assistants_img_2 {
display: none;
}
}
}
.submit_btn {
position: absolute;
right: 0rpx;
bottom: 10rpx;
image {
width: 55rpx;
height: 55rpx;
}
}
.active {
text {
color: $themeBgColor;
}
.assistants_img_1 {
display: none !important;
}
.assistants_img_2 {
display: block !important;
}
}
.message_wrap {
position: relative;
width: 100%;
// background: #fff;
z-index: 99;
padding: 0 30rpx;
height: 85vh;
}
.message_title {
text-align: center;
font-size: 34rpx;
color: #333;
line-height: 50rpx;
display: block;
font-weight: bold;
padding: 10rpx 0;
}
.message-container-block {
padding-top: 20rpx;
padding-bottom: 80px;
font-size: 30rpx;
}
.message-container {
display: inline;
line-height: 48rpx;
}
/* 自定义的loading效果 */
.loading-spinner {
margin-top: 10rpx;
border: 2px solid #f3f3f3;
/* 灰色背景 */
border-top: 2px solid #3498db;
/* 蓝色顶部 */
border-radius: 50%;
width: 16px;
height: 16px;
animation: spin 1s linear infinite;
/* 旋转动画 */
}
/* 旋转动画 */
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.bold-text {
display: block;
font-weight: bold;
font-size: 28rpx;
/* 增大字号 */
}
h3 {
font-size: 36rpx;
font-weight: bold;
}
h3 {
font-size: 32rpx;
}
.red-text {
color: red;
font-size: 28rpx;
/* 增大字号 */
}
.message-right {
display: block;
text-align: right;
margin: 30rpx 0;
text {
display: inline-block;
padding: 20rpx;
line-height: 38rpx;
background-color: rgba(81, 136, 229, 0.2);
border-radius: 15rpx;
color: #333;
font-size: 28rpx;
text-align: left;
}
}
.drawer-content {
height: 100vh;
display: flex;
flex-direction: column;
}
.list_content {
padding: 70rpx 20rpx 30rpx;
overflow-y: auto;
}
.list_item {
padding: 18rpx 10rpx;
}
.text_item {
display: block;
width: 100%;
font-size: 30rpx;
line-height: 40rpx;
padding: 0 10rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.null_text {
display: block;
text-align: center;
font-size: 30rpx;
color: #999;
padding-top: 150rpx;
}
.active_item {
background: #d8e6ff;
border-radius: 15rpx;
text {
color: #5188e5;
}
}
.folder_popup {
z-index: 9999;
.popup-content {
padding: 30rpx;
width: 550rpx;
background: #fff;
border-radius: 10rpx;
.popup-top {
padding: 15rpx;
display: flex;
align-items: center;
background: #5188e5;
border-radius: 10rpx;
color: #fff;
font-size: 28rpx;
line-height: 45rpx;
.uni-icons {
margin-right: 2rpx;
}
}
.popup-list {
.item-list {
padding: 15rpx;
background: #d8e6ff;
border-radius: 10rpx;
font-size: 28rpx;
line-height: 45rpx;
color: #5188e5;
margin-top: 15rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
position: relative;
text {
position: absolute;
right: 20rpx;
top: 12rpx;
font-size: 22rpx;
line-height: 45rpx;
color: #ff7800;
}
}
.popup-scroll {
max-height: 330rpx;
}
}
}
}
.add_folder_name {
font-size: 30rpx;
line-height: 45rpx;
color: #5188e5;
}
.add_folder_input {
margin-top: 20rpx;
input {
height: 70rpx;
line-height: 70rpx;
padding: 0 20rpx;
font-size: 26rpx;
color: #303030;
border-radius: 10rpx;
border: 1rpx solid #ddd;
box-sizing: border-box;
}
.custom-placeholder {
font-size: 26rpx;
}
}
.add_folder_btn {
width: 50%;
margin: 25rpx auto 0;
background: #5188e5;
border-radius: 50rpx;
font-size: 26rpx;
color: #fff;
line-height: 70rpx;
}
.checkbox-item {
display: flex;
align-items: center;
margin-top: 20rpx;
checkbox {
transform: scale(0.55);
/deep/.uni-checkbox-input {
border: 1rpx solid $themeColor;
margin-right: 0;
}
}
text {
color: #666;
font-size: 26rpx;
margin-left: -5rpx;
}
}
//基因模糊
.tags-block {
width: calc(100% - 255rpx);
line-height: 46rpx;
padding: 12rpx 20rpx;
border-radius: 50rpx;
border: 1rpx solid #777778;
box-sizing: border-box;
input {
border: none !important;
padding: 5rpx 10rpx !important;
height: 50rpx !important;
}
}
.tags-container {
width: 100%;
display: flex;
flex-wrap: wrap;
}
.tag {
margin: 5rpx;
display: flex;
align-items: center;
background-color: #d8e6ff;
border-radius: 20rpx;
color: $themeColor;
padding: 0 15rpx;
font-size: 24rpx;
line-height: 38rpx;
}
.tag-close {
font-size: 24rpx;
font-weight: bold;
padding-left: 10rpx;
}
.result-list {
background: #fff;
width: calc(100% - 200rpx);
max-height: 325rpx;
border: 1px solid #eee;
border-radius: 10rpx;
margin-top: -30rpx;
float: right;
}
.result-item {
padding: 18rpx 20rpx;
border-bottom: 1px solid #f5f5f5;
font-size: 26rpx;
line-height: 30rpx;
}
.result-item:last-child {
border-bottom: 0;
}
.vip_count {
font-size: 26rpx;
color: red;
text-indent: 0;
text {
display: block;
}
}
.vip_count_block {
display: inline-block;
text-indent: 0;
padding-top: 10rpx;
}
.aiFlag {
position: absolute;
bottom: 55px;
left: 20px;
width: calc(100% - 40px);
font-size: 11px;
line-height: 16px;
color: #f69e12;
z-index: 999;
background: rgba(254, 243, 225, 0.8);
border: 1px solid #f2d7aa;
padding: 5px;
border-radius: 6px;
}
.in {
border: 1rpx solid #eeeeee;
border-radius: 8rpx;
width: calc(100% - 200rpx);
}
.shangpin_editor {
width: 100%;
}
/deep/.h1_box {
height: 24px;
margin-top: 40rpx;
h1 {
margin: 0 !important;
font-size: 20px;
line-height: 24px;
}
}
#editor {
height: 300px;
border: 1px solid #ccc;
}
.ql-container {
height: auto;
min-height: auto;
}
.editor-wrapper {
// background-color: #f0f0f080;
padding: 20rpx;
box-sizing: border-box;
border-radius: 20rpx;
border: 0.5px solid #777778;
}
.footer_box {
background: #fff;
padding-top: 10rpx;
height: 100rpx;
position: fixed;
bottom: 0;
left: 0;
width: 100%;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
z-index: 502;
box-sizing: content-box;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
box-shadow: 0 1px 15px rgba(0, 0, 0, 0.1);
}
.footer_bg {
background-color: #fff;
box-shadow: 0 0px 10px 1px #0000001a;
}
.footer_item {
position: relative;
flex: 1;
.button {
width: 88%;
background-color: #1985fd;
margin: auto auto;
margin-top: 10rpx;
border-radius: 50px;
line-height: 40px;
height: 40px;
text-align: center;
color: #fff;
font-weight: bold;
}
.savebutton {
background-color: #e4f0ff;
color: #1985fd;
}
}
/deep/.u-upload__button {
background-color: #fff;
.uicon-camera-fill {
color: #5188e5 !important;
}
}
.analysis_box {
padding-bottom: 40px;
width: 100%;
background-color: #fff;
border: 4rpx solid #188bff !important;
border-radius: 20rpx;
height: 88vh;
border-radius: 10px;
box-sizing: border-box !important;
uni-textarea {
border: none !important;
}
.analysis_title {
display: flex;
align-items: center;
padding: 18rpx 32rpx 0 16rpx;
color: #1781ff;
font-size: 18px;
font-weight: 700;
}
}
/deep/.home_wrap_analysis {
height: 92vh;
.home_form {
padding-bottom: 0px;
}
.form_item {
margin-bottom: 0 !important;
textarea {
// padding-top: 20rpx;
// height: 80vh !important;
}
.uni-textarea-wrapper {
// height: 100% !important;
}
}
.submit_btn {
padding:0 40rpx;
position: absolute;
right: 24rpx;
bottom: 24rpx;
background-color: #1985fd;
margin: auto auto;
margin-top: 10rpx;
border-radius: 20rpx;
line-height: 62rpx;
height: 62rpx;
text-align: center;
color: #fff;
// font-weight: bold;
}
}
</style>