Files
nuttyreading-master-html/src/views/modules/medicalrecords/addCertificate.vue
2025-08-05 14:49:37 +08:00

1759 lines
58 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>
<div class="mod-config">
<el-drawer
:title="
`${
type == 'edit'
? '编辑医案'
: type == 'add'
? '新增医案'
: `医案详情${
addCertificateForm.state == 1 ? ' ( 待审核 ) ' : ' ( 已拒绝 ) '
}`
}`
"
:visible.sync="dialogVisible"
:close-on-click-modal="false"
:wrapperClosable="true"
:before-close="handleClose"
custom-class="yianDrawer"
size="1200px"
>
<div
v-if="dialogVisible"
style="padding: 0 20px;box-sizing: border-box;height: calc(100% - 40px);overflow-y: auto;"
:style="
`
${
addCertificateForm.state == 2 || !showMessages ? 'height:100%;' : ''
}
`
"
>
<div style="width:300px !important;float:right;background:#fafafa" v-if="markList.length>0">
<el-timeline style="padding-left:10px;margin-top:14px" :reverse="true">
<el-timeline-item
v-for="(activity, index) in markList"
:key="index"
:timestamp="activity.time"
>
<p style="font-size:12px;color:#f56c6c;margin:0;margin-bottom:4px" v-if="activity.state == 2"
>已拒绝</p
>
<p style="font-size:12px;color:#17b3a3;margin:0;margin-bottom:4px" v-if="activity.state == 3"
>已通过</p
>
{{ activity.mark }}
</el-timeline-item>
</el-timeline>
</div>
<div class="medical_box" :style="
`
${
markList.length>0? 'width:calc(100% - 320px);float:left' : ''
}
`
">
<!-- 触发按钮 -->
<p
style="cursor: pointer;margin: 0;margin-bottom: 10px;"
v-if="isShowWord"
>
<span @click="triggerUpload">上传 Word</span>
<img
src="../../../assets/img/word-iocn.png"
alt=""
@click="triggerUpload"
/>
<span
style="color:red;float: right;"
v-if="messageList.length > 0"
@click="messageList = []"
>
<i class="el-icon-delete"></i>
清空已识别的医案
</span>
</p>
<!-- 隐藏上传框 -->
<input
type="file"
ref="uploadInput"
accept=".docx"
@change="handleUpload"
style="display: none"
/>
<div
style="display: flex;align-items: center;justify-content: flex-start;flex-wrap: wrap;"
v-if="isShowWord"
>
<div
v-for="(v, i) in messageList"
class="wordItem"
@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: 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
>
</p>
<div
style=" overflow: hidden;font-size: 13px;padding: 10px 10px 0;box-sizing: border-box;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-height: 1.5;
max-height: calc(1.5em * 3);
text-overflow: ellipsis;
word-break: break-word; /* 可选:精确限制高度,兼容性更好 */"
>
{{ 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>
</div>
<template v-if="!showMessages">
<div class="home_wrap home_wrap_analysis">
<div class="home_form" style="position: relative">
<div
class="form_item"
style="
display: flex;
align-items: flex-start;
justify-content: space-between;
"
>
<!-- <text>医案信息</text> -->
<!-- 固定标题和输入框部分 -->
<div class="analysis_box">
<div
class="analysis_title"
style="width: 100%;overflow: hidden;"
>
智能分析医案
</div>
<!-- 固定的输入框部分 -->
<div
style="height: calc(100% - 20px);padding:15px 15px 0;box-sizing: border-box;"
>
<!-- <quill-editor
style=" min-height: 95% !important;"
placeholder="请输入医案到此处,将自动解析医案信息"
v-model="message"
ref="myQuillEditor"
:options="editorOption"
>
</quill-editor> -->
<textarea
style=" min-height: 95% !important;"
placeholder="请输入医案到此处,将自动解析医案信息"
v-model="message"
ref="myQuillEditor"
:options="editorOption"
>
</textarea>
<el-button
type="primary"
size="mini"
@click="submit"
style="float: right;margin-right: 10px;margin-top: 4px;background-color: #1781ff;"
>解析医案</el-button
>
</div>
</div>
</div>
</div>
<!-- 搜索结果列表 -->
</div>
</template>
<template v-else>
<el-alert
v-if="tishi"
:title="
loading
? '解析预计耗时约50秒,请耐心等待,也可在草稿箱中查看内容'
: '好的结合您的医案下面是解析后的结果。5秒后自动关闭'
"
:type="loading ? 'warning' : 'success'"
show-icon
>
</el-alert>
<template v-if="!loading">
<!-- <div
v-if="
addCertificateForm.mark &&
(addCertificateForm.mark.state == 2 ||
addCertificateForm.state == 3)
"
style="padding:4px 10px;border-radius: 4px;white-space: wrap;"
:style="
`color:${currentNode.data.color ? currentNode.data.color : ''};
`
"
>
审核备注:{{ addCertificateForm.mark }}
</div> -->
<el-form
:rules="dataRule"
:model="addCertificateForm"
ref="addCertificateForm"
label-width="120px"
>
<!-- <div style="background-color: #f0f0f0;padding:0 10px;box-sizing: border-box;color: #000;">
<p>绑定用户</p>
</div> -->
<div
v-if="pageType == 'label'"
style="display:flex;align-items:center;justify-content:space-between"
>
<el-form-item
style="width: 50%;"
label="手机号/邮箱:"
prop="userKey"
class="form_item"
>
<div style="display: flex;align-items: center;">
<el-autocomplete
size="small"
v-if="isEdit"
style="width: 100%;"
v-model="addCertificateForm.userKey"
:fetch-suggestions="loadAll"
placeholder="请输入手机号/邮箱"
@select="handleSelect"
>
<template #default="{ item }">
<div class="custom-item">
<span>{{ item.tel ? item.tel : item.email }}</span>
<span
style="color: gray; margin-left: 10px;"
v-if="item.name"
>({{ item.name }})</span
>
</div>
</template>
</el-autocomplete>
<span v-if="!isEdit">{{
addCertificateForm.userKey
}}</span>
</div>
</el-form-item>
<el-form-item
label="用户姓名:"
style="width: 50%;"
v-if="addCertificateForm.userId"
prop="user"
class="form_item"
>
<div>
<!-- <span
style="width: 110px;display: inline-block;text-align: right;"
>用户姓名:</span
> -->
{{
addCertificateForm.userName
? addCertificateForm.userName
: "-"
}}
</div></el-form-item
>
</div>
<template
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
label="手机号/邮箱:"
prop="user"
class="form_item"
>
<div style="display: flex;align-items: center;">
{{ addCertificateForm.userKey }}
</div>
</el-form-item>
<el-form-item
label="用户姓名:"
style="width: 50%;"
prop="user"
class="form_item"
>
<div>
{{
addCertificateForm.userName
? addCertificateForm.userName
: "-"
}}
</div></el-form-item
> -->
<el-form-item label="医案分类" prop="user" class="form_item">
<div>
<el-cascader
size="mini"
style="width: 100%;"
:show-all-levels="false"
v-model="addCertificateForm.labelId"
:props="{
value: 'id',
label: 'title'
}"
filterable
:options="cateOptions"
@change="selectLabelId"
placeholder="医案分类"
></el-cascader></div
></el-form-item>
</template>
<div
class="flexbox width100"
style="display: flex;align-items: center;"
>
<el-form-item
label="标题:"
label-width="110px"
prop="title"
style="width: 100%;"
>
<el-input
v-if="type != 'detail'"
clearable
size="small"
v-model="addCertificateForm.title"
placeholder="请输入医案标题"
style="width: 100%;"
></el-input>
<div v-else>
{{ addCertificateForm.title }}
</div>
</el-form-item>
</div>
<!-- <el-form-item label="课程名称:" prop="course" class="form_item">
<el-button plain type="primary" @click="selectCourse('addCertificateForm')"
size="mini">选择</el-button>
<span style="margin-left: 20px"></span>
<br/>
<div v-if="addCertificateForm.courseId" style="font-weight: bold;margin-top: 20px;display: flex;align-items: center;justify-content: space-between;"><p><img v-if="addCertificateForm.courseImg" :src="addCertificateForm.courseImg" alt=""style="width: 30px;height: 40px;margin-right: 20px;">{{ addCertificateForm.courseName }}</p><span @click="clearCourse" style="color: red;cursor: pointer;"><i class="el-icon-delete" style="margin-right: 4px;"></i> 删除</span></div>
</el-form-item> -->
<!-- <el-form-item label="医案编号" prop="certificateNo" class="form_item">
<el-input
v-model="addCertificateForm.certificateNo"
placeholder="请输入医案编号"
style="width: 400px;"
></el-input>
</el-form-item> -->
<el-form-item
label="医案详情:"
label-width="110px"
class="form_item"
>
<div style="padding-top: 15px;">
<div
v-for="(html, key) in record"
:key="key"
style="padding: 2px; margin-bottom: 4px;box-sizing: border-box;"
>
<!-- 显示字段标题 -->
<div
class="h1_box"
:class="type == 'detail' ? 'h1_box_detail' : ''"
v-html="`${getTitleHtml(html, key)}`"
style="margin-top: 0;margin-bottom: 10px; font-weight: bold;display: flex;align-items: center;"
></div>
<!-- 编辑区域 -->
<quill-editor
v-model="editableMap[key]"
ref="myQuillEditor"
:options="editorOption"
class="shangpin_editor"
v-if="type != 'detail'"
>
</quill-editor>
<div
class="detail_info_medical"
v-else
v-html="
editableMap[key] ? editableMap[key] : '<p>无</p>'
"
></div>
</div>
<!-- <h3 style="margin-top: 40px;">✅ 保存后的结果JSON 格式预览)</h3> -->
</div>
<!-- <quill-editor
v-model="detailContent"
ref="myQuillEditor2"
:options="editorOption"
class="shangpin_editor"
>
</quill-editor> -->
</el-form-item>
<el-form-item
label="上传图片:"
label-width="110px"
class="form_item custom-upload-box"
v-if="dialogVisible"
>
<!-- <template v-for="(file, i) in fileList" v-if="type == 'detail'">
<img
style="width: 60px;height: 60px;border-radius: 6px;margin: 0 8px 8px 0;"
class="el-upload-list__item-thumbnail"
:src="file.url"
alt=""
/>
</template> -->
<div
v-if="fileList.length == 0 && type == 'detail'"
style="line-height: 60px;"
>
暂无图片
</div>
<el-upload
v-if="type != 'detail'"
class="custom-upload"
multiple
:action="baseUrl + '/oss/fileoss'"
list-type="picture-card"
accept="image/png, image/jpeg"
:file-list="fileList"
:on-success="onSuccessImg"
:before-upload="beforeUpload"
:on-progress="onProgress"
>
<i slot="default" class="el-icon-plus"></i>
<div slot="file" slot-scope="{ file }">
<img
class="el-upload-list__item-thumbnail"
:src="file.url"
alt=""
/>
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<i class="el-icon-zoom-in"></i>
</span>
<span
v-if="!disabled"
class="el-upload-list__item-delete"
@click="handleRemove(file)"
>
<i class="el-icon-delete"></i>
</span>
</span>
<!-- 上传中的加载动画 -->
<div v-if="file.uploading" class="loading-spinner">
<i class="el-icon-loading"></i>
</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(',')"
>
</el-image>
</template>
<!-- <div class="flexBox" style="width:100%;justify-content: space-between;">
<div class="" style="display:flex">
<div
style="display:flex; align-items:center; width:100%;justify-content:center">
<div style="margin-right:15px">封面图</div>
<div>
<el-upload class="avatar-uploader" :action="baseUrl + '/oss/fileoss'"
:show-file-list="false" :on-success="handlePicSuccess">
<img v-if="fimages" :src="fimages" class="avatar" />
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</div>
<div>
<div v-if="fimages != ''">
<el-tag class="delImgBtn" @click="delImg()"
type="danger">清空图片</el-tag>
</div>
</div>
</div>
</div>
</div> -->
</el-form-item>
</el-form>
</template>
<div v-else v-loading="loading" style="height: 95%;"></div>
</template>
</div>
</div>
<div
class="demo-drawer__footer"
v-if="
type == 'edit' || (type == 'add' && showMessages && loading == false)
"
>
<div class="drawer_footer_box">
<el-button
style="float: right;margin:0 10px;"
type="primary"
size="mini"
@click="handleSubmit('addCertificateForm')"
>提 交</el-button
>
<el-button
size="mini"
@click="dialogVisible = false"
style="float: right;"
>取 消</el-button
>
</div>
</div>
<div
class="demo-drawer__footer"
v-if="type == 'detail' && addCertificateForm.state == 1"
>
<div class="drawer_footer_box">
<!-- <el-checkbox v-model="addCertificateForm.train" true-label="1" false-label="0">是否加入Ai训练库</el-checkbox> -->
<el-button
style="float: right;margin:0 10px;"
type="primary"
size="mini"
@click="handleReview('approved', 1)"
>审核通过</el-button
>
<el-button
size="mini"
type="danger"
@click="handleReview('rejected', 0)"
style="float: right;"
>审核拒绝</el-button
>
</div>
</div>
</el-drawer>
<el-dialog
:title="`审核${reviewType == 'approved' ? '通过' : '拒绝'}备注`"
:visible.sync="dialogMarkVisible"
width="400px"
:beforeClose="beforeClose"
>
<el-input
v-model="addCertificateForm.mark"
:placeholder="
`请输入审核${reviewType == 'approved' ? '通过' : '拒绝'}备注`
"
:clearable="true"
></el-input>
<el-checkbox
:true-label="1"
:false-label="0"
v-model="addCertificateForm.train"
style="margin-top: 20px;"
v-if="reviewType == 'approved'"
>是否加入 Ai 训练库</el-checkbox
>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogMarkVisible = false" size="mini"
>取消</el-button
>
<el-button
:type="`${reviewType == 'approved' ? 'primary' : 'danger'}`"
@click="handleReviewSave"
size="mini"
>{{ reviewType == "approved" ? "通过" : "拒绝" }}</el-button
>
</span>
</el-dialog>
<el-dialog :visible.sync="dialogVisibleImg" :append-to-body="true">
<img
width="100%"
:src="dataForm.productImages"
alt=""
/>
</el-dialog>
</div>
</template>
<script>
import { quillEditor } from "vue-quill-editor";
import global from "../../common/common.vue"; //引入共用组间
import debounce from "lodash/debounce"; //导入lodash中的debounce
import AddOrUpdate from "@/views/components/commonBookTags/bookTagsForm.vue";
import commonShop from "@/views/components/commonBookTags/shopproduct.vue";
import commonShopTable from "@/views/components/commonBookTags/shopproductTable.vue";
import commonTree from "@/views/components/commonBookTags/tags.vue";
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";
const toolbarOptions = [
["bold", "italic", "underline", "strike"], // 加粗,斜体,下划线,删除线
["blockquote", "code-block"], //引用,代码块
[{ header: 1 }, { header: 2 }], // 几级标题
[{ list: "ordered" }, { list: "bullet" }], // 有序列表,无序列表
[{ script: "sub" }, { script: "super" }], // 下角标,上角标
[{ indent: "-1" }, { indent: "+1" }], // 缩进
[{ direction: "rtl" }], // 文字输入方向
[{ size: ["small", false, "large", "huge"] }], // 字体大小
[{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
[{ color: [] }, { background: [] }], // 颜色选择
[
{
font: [
"SimSun",
"SimHei",
"Microsoft-YaHei",
"KaiTi",
"FangSong",
"Arial"
]
}
], // 字体
[{ align: [] }], // 居中
["clean"], // 清除样式,
["link", "image"] // 上传图片、上传视频
];
// import dialogComponent from './seckillprodrelation'
export default {
props: ["data", "pageType", "dataInfo", "labelId", "currentNode"],
data() {
return {
dataForm:{},
isShowWord: false,
imagePreviews: false,
record: {},
loading: false,
tishi: false,
message: "",
currentMedicalWordImageList: [],
currentMedicalWordImageStr: "",
messageList: [],
showMessages: false,
editableMap: {}, // 存储每个字段的内部可编辑内容
editorOption: {
modules: {
toolbar: false
// history: {
// delay: 1000,
// maxStack: 50,
// userOnly: false
// },
// toolbar: {
// container: toolbarOptions,
// handlers: {
// image: function (value) {
// if (value) {
// // 调用element的图片上传组件
// document.querySelector('.avatar-uploader input').click()
// } else {
// this.quill.format('image', false)
// }
// }
// }
// },
},
placeholder: "请输入.."
},
dataRule: {
userKey: [
{
required: true,
message: "请输入手机号/邮箱"
// trigger: "change",
}
],
title: [
{
required: true,
message: "请输入标题"
// trigger: "change",
}
]
},
isUploading: false, // 上传过程中是否显示加载动画
isEdit: false, // 上传过程中是否显示加载动画
dialogImageUrl: "",
dialogVisibleImg: false,
disabled: false,
restaurants: [],
fileList: [],
options: [],
cateOptions: [],
state: "",
timeout: null,
addCertificateForm: {},
baseUrl: global.baseUrl,
isEdit: false,
checkAll: false,
isIndeterminate: true,
dialogVisible: false,
dialogMarkVisible: false,
urlList: {},
activeName: "first",
reviewType: "",
addForm: {},
audioFileList: [],
isFresh: false,
pollInterval: null,
type: "",
detailContent: "",
medicalId: "",
medicalRecords: {},
content: "",
markList: []
};
},
components: {
AddOrUpdate,
commonShop,
commonTree,
commonShopTable,
quillEditor
},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
}
},
activated() {
const quill = this.$refs.myQuillEditor.quill;
// 禁用编辑器
quill.disable(); // 这会禁用编辑器的所有功能,包括输入和修改
this.isEdit = false;
// 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 = [
"零",
"一",
"二",
"三",
"四",
"五",
"六",
"七",
"八",
"九"
];
const cnUnits = ["", "十", "百", "千", "万", "亿"];
if (n === 0) return cnNums[0];
let result = "";
const digits = String(n)
.split("")
.reverse();
for (let i = 0; i < digits.length; i++) {
const num = Number(digits[i]);
const unit = num === 0 ? "" : cnUnits[i];
result = (num === 0 ? cnNums[num] : cnNums[num] + unit) + result;
}
// 去除多余的“零”
result = result.replace(/零+/g, "零").replace(/零$/g, "");
result = result.replace(/^一十/, "十"); // 10-19 处理为 十一、十二...
return result;
},
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 = [];
this.$refs.uploadInput.value = null;
this.$refs.uploadInput.click();
},
// 处理上传文件
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);
this.messageList = arr;
loading.close();
})
.catch(() => {
loading.close();
});
},
beforeClose() {
this.dialogMarkVisible = false;
},
remoteMethod(query) {
console.log(query, "query", this.addCertificateForm.key);
// return false
if (this.addCertificateForm.key !== "") {
let data = {
title: query //关键字
};
this.totalLaoding = true;
this.$http({
url: this.$http.adornUrl("/master/userManage/courseAndChildrenList"),
method: "post",
data: this.$http.adornData(data)
}).then(({ data }) => {
if (data && data.code === 0) {
this.options = data.list;
} else {
this.options = [];
}
this.totalLaoding = false;
if (data.code !== 0) return this.$message.error(data.msg);
});
} else {
this.options = [];
this.totalLaoding = false;
}
},
getCateList() {
this.$http({
url: this.$http.adornUrl(
"/master/medicalRecords/getMedicalRecordsLabelList"
),
method: "post",
data: this.$http.adornData({})
}).then(({ data }) => {
if (data && data.code === 0) {
this.cateOptions = data.Medicals;
} else {
this.cateOptions = [];
}
this.totalLaoding = false;
if (data.code !== 0) return this.$message.error(data.msg);
});
},
loadAll(queryString, cb) {
this.addCertificateForm.userId = "";
this.addCertificateForm.userName = "";
if (queryString == "") {
return false;
}
this.$http({
// url: this.$http.adornUrl('/book/user/list'),
url: this.$http.adornUrl("/book/user/getUserList"),
method: "post",
data: this.$http.adornData({
page: 1,
limit: 9999,
key: queryString
})
}).then(({ data }) => {
if (data && data.code === 0) {
var arr = data.user.records;
console.log("arr at line 467:", arr);
cb(arr);
} else {
cb([]);
}
});
},
createStateFilter(queryString) {
return state => {
return (
state.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
);
};
},
handleSelect(item) {
console.log(item);
this.addCertificateForm.userKey = item.tel ? item.tel : item.email;
this.addCertificateForm.userName = item.name;
this.addCertificateForm.userId = item.id;
},
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")
? str + (div.querySelector("h1").outerHTML || "<h1></h1>")
: "";
},
saveAll() {
for (const key in this.record) {
const titleHtml = this.getTitleHtml(this.record[key]);
this.record[key] = titleHtml + this.editableMap[key];
}
alert("保存成功!");
},
init(type, data) {
this.showMessages = false;
this.markList = [];
this.messageList = [];
this.currentMedicalWordImageList = [];
this.currentMedicalWordImageStr = "";
this.message = "";
this.tishi = false;
this.loading = false;
this.getCateList();
this.type = type;
console.log("data at line 372:", data);
this.addCertificateForm = {};
this.fileList = [];
var recordData = {
information: "<h1>一般信息</h1>",
chiefComplaint: "<h1>主诉</h1>",
historyOfPresentIllness: "<h1>现病史</h1>",
pastHistory: "<h1>既往史</h1>",
personalAndFamilyHistory: "<h1>个人史与家族史</h1>",
physicaExamination: "<h1>体格检查</h1>",
diagnosis: "<h1>诊断</h1>",
treatmentPlan: "<h1>治疗和后续治疗</h1>",
treatmentPlan: "<h1>其他</h1>"
};
this.isEdit = type == "edit" || type == "add" ? true : false;
if (type == "add") {
this.isShowWord = true;
this.record = {
...recordData
};
} else {
this.isShowWord = false;
this.showMessages = true;
}
if (data) {
if (type == "edit" || type == "detail") {
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
};
}
this.addCertificateForm = {
...data
};
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(
","
);
}
if (this.addCertificateForm.mark) {
this.markList = JSON.parse(this.addCertificateForm.mark);
this.addCertificateForm.mark=''
}
} else {
this.addCertificateForm = {};
}
if (this.pageType == "label") {
if (data.userId) {
this.addCertificateForm.userKey = data.user.tel
? data.user.tel
: data.user.email;
this.addCertificateForm.userName = data.user.name;
this.addCertificateForm.userId = data.user.id;
}
} else {
this.addCertificateForm.userKey = this.dataInfo.tel
? this.dataInfo.tel
: this.dataInfo.email;
this.addCertificateForm.userName = this.dataInfo.name;
this.addCertificateForm.userId = this.dataInfo.id;
}
console.log(
"this.addCertificateForm at line 465:",
this.addCertificateForm
);
for (const key in this.record) {
this.$set(this.editableMap, key, this.getInnerHtml(this.record[key]));
}
this.dialogVisible = true;
},
handleReviewSave() {
var recordData = { ...this.record };
// for (const key in recordData) {
// const titleHtml = this.getTitleHtml(recordData[key]);
// recordData[key] = titleHtml + this.editableMap[key];
// }
const label = this.addCertificateForm.labelId;
const value = Array.isArray(label) ? label[label.length - 1] : label;
const formatFullTime = date => {
const pad = (n, len = 2) => n.toString().padStart(len, "0");
return (
`${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(
date.getDate()
)} ` +
`${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(
date.getSeconds()
)}.${pad(date.getMilliseconds(), 3)}`
);
};
const now = new Date();
const timeStamp = now.getTime(); // 毫秒级时间戳
const timeStr = formatFullTime(now); // 格式化字符串
var markList = [
...this.markList,
{
mark: this.addCertificateForm.mark,
time: timeStr,
state: this.reviewType == "approved" ? 3 : 2
}
];
var data = {
labelId: value,
img:
this.fileList.length > 0
? this.addCertificateForm.imageList.toString()
: "",
title: this.addCertificateForm.title,
userId: this.addCertificateForm.userId,
train: this.addCertificateForm.train, //是否加入ai训练库0否1是
mark: JSON.stringify(markList), //备注
state: this.reviewType == "approved" ? 3 : 2, //备注
...recordData
};
// if(this.record.)
this.$http({
url: this.$http.adornUrl("/master/medicalRecords/editMedicalRecords"),
method: "post",
data: this.$http.adornData({
...data,
data: this.addCertificateForm.data
? this.addCertificateForm.data
: "",
id: this.addCertificateForm.id
})
}).then(({ data }) => {
if (data && data.code === 0) {
this.$message({
message: "操作成功",
type: "success"
});
this.dialogVisible = false;
this.dialogMarkVisible = false;
this.$nextTick(() => {
this.$emit("refresh");
});
} else {
this.$message.error(data.msg);
}
});
},
handleReview(type, typeValue) {
// approved 通过
// rejected 拒绝
this.addCertificateForm.mark=''
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`);
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;
}
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: "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;
this.sendQuestion();
} else {
this.loading = false;
this.$message.error("请重新解析");
}
})
.catch(() => {
this.loading = false;
this.$message.error("请重新解析");
});
},
//交谈请求,获取回答
sendQuestion() {
//清空消息记录
this.showMessages = true;
var that = this;
//展示提示语
this.tishi = true;
this.isShowWord = false;
this.messageList = [];
const poll = () => {
this.getMedicalDetail(() => {
// 停止轮询
clearInterval(this.pollInterval);
this.pollInterval = null;
setTimeout(() => {
this.tishi = false;
}, 5000);
});
};
// 每5秒发送一次请求直到收到正确的响应
this.pollInterval = setInterval(poll, 5000);
//调用后端 SSE 接口,发送问题并接收实时回答
// this.startSSE(params);
},
getMedicalDetail(fn) {
//清空消息记录
this.$http({
url: this.$http.adornUrl(
"/common/medicalRecords/medicalRecordsQuerySplit"
),
method: "post",
data: this.$http.adornData({
id: this.medicalId
})
})
.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 &&
res.data.medicalRecords.data != ""
) {
console.log(res, "999999");
var data = { ...res.data.medicalRecords };
this.loading = false;
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])
);
}
// 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();
// 滚动到最底部锚点
// that.$nextTick(() => {
// that.scrollToBottom();
// });
// 停止轮询
if (fn) {
fn();
}
}
})
.catch(error => {
console.log("请求出错:", error);
});
//调用后端 SSE 接口,发送问题并接收实时回答
// this.startSSE(params);
},
handleSubmit: debounce(async function() {
// this.addCertificateForm
console.log("this.addCertificateForm at line 479:", this.editableMap);
this.$refs["addCertificateForm"].validate(valid => {
if (valid) {
if (!this.addCertificateForm.userId && this.pageType == "label") {
this.$message.error("请选择用户");
return false;
}
if (this.editableMap.chiefComplaint == "") {
const titleHtml = this.getTitleHtml(
this.record["chiefComplaint"]
).replace(/<[^>]*>/g, "");
this.$message.error("请输入 " + titleHtml);
return false;
}
if (this.editableMap.historyOfPresentIllness == "") {
const titleHtml = this.getTitleHtml(
this.record["historyOfPresentIllness"]
).replace(/<[^>]*>/g, "");
this.$message.error("请输入 " + titleHtml);
return false;
}
if (this.editableMap.physicaExamination == "") {
const titleHtml = this.getTitleHtml(
this.record["physicaExamination"]
).replace(/<[^>]*>/g, "");
this.$message.error("请输入 " + titleHtml);
return false;
}
if (this.editableMap.treatmentPlan == "") {
const titleHtml = this.getTitleHtml(
this.record["treatmentPlan"]
).replace(/<[^>]*>/g, "");
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]);
recordData[key] = titleHtml + this.editableMap[key];
}
var data = {
img:
this.fileList.length > 0
? this.addCertificateForm.imageList.toString()
: "",
title: this.addCertificateForm.title,
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.currentNode.data.id == "caogao"
? "/master/medicalRecords/editMedicalRecords"
: "/master/medicalRecords/addMedicalRecords"
),
method: "post",
data: this.$http.adornData({ ...data })
}).then(({ data }) => {
if (data && data.code === 0) {
this.$message({
message: "操作成功",
type: "success"
});
this.dialogVisible = false;
this.$nextTick(() => {
this.$emit("refresh");
});
} else {
this.$message.error(data.msg);
}
});
}
});
}, 200),
onSuccessImg(response, file, fileList) {
// 上传成功后,直接将返回的 URL 放到 file 对象中
file.uploading = false;
file.url = response.url; // 假设返回的数据包含文件的 url 地址
this.fileList = fileList; // 更新 fileList
this.addCertificateForm.imageList = fileList.map(e => e.url);
console.log(
"this.addCertificateForm.imageList at line 713:",
this.addCertificateForm.imageList
);
},
beforeUpload(file) {
// 在文件上传之前,设置文件的上传状态
file.uploading = true;
},
onProgress(event, file, fileList) {
// 进度更新时,文件状态可以继续保持上传中
file.uploading = true;
},
handleRemove(file) {
this.fileList = this.fileList.filter(f => f.uid !== file.uid); // 删除文件
this.addCertificateForm.imageList = this.fileList.map(e => e.url);
console.log(
"this.addCertificateForm.imageList at line 727:",
this.addCertificateForm.imageList
);
},
handleDownload(file) {
const link = document.createElement("a");
link.href = file.url;
link.download = file.name;
link.click();
},
selectChange(val) {
console.log("options", this.options);
// this.getCate(val)
},
handlePictureCardPreview(file) {
this.dataForm.productImages = file.url;
this.dialogVisibleImg = true;
},
handleClose(done) {
done();
this.$emit("refresh");
}
},
beforeDestroy() {
clearInterval(this.pollInterval);
}
};
</script>
<style lang="less" scoped>
.yianDrawer {
.width100 {
width: 100% !important;
}
.el-form-item {
margin-bottom: 15px;
}
/deep/.el-upload-list--picture-card .el-upload-list__item {
width:80px !important;
height:80px !important;
line-height:80px !important;
}
/deep/.el-upload--picture-card {
width:80px !important;
height:80px !important;
line-height:80px !important;
}
}
/deep/.yianDrawer header {
margin-bottom: 10px !important;
}
/deep/.custom-upload {
min-height: 120px !important;
}
/deep/.custom-upload .el-upload--picture-card {
width:80px !important;
height:80px !important;
line-height:80px !important;
}
/deep/.custom-upload .el-upload-list--picture-card .el-upload-list__item {
width:80px !important;
height:80px !important;
line-height:80px !important;
}
/deep/.custom-upload-box .el-form-item__label {
line-height: 60px !important;
}
/deep/.h1_box {
height: 24px;
h1 {
margin: 0 !important;
font-size: 16px;
line-height: 24px;
}
}
/deep/ .detail_info_medical {
li {
line-height: 24px !important;
}
ul {
margin: 0 !important;
list-style-type: disc !important; /* 强制使用实心圆点 */
}
p {
margin: 0 !important;
}
}
.analysis_box {
padding-bottom: 10px;
width: 100%;
background-color: #fff;
border: 1px solid #188bff !important;
border-radius: 20px;
min-height: 84vh;
height: auto;
border-radius: 10px;
box-sizing: border-box !important;
textarea {
border: none !important;
}
.analysis_title {
display: flex;
align-items: center;
padding: 18px 32px 0 16px;
color: #1781ff;
font-size: 18px;
font-weight: 700;
}
}
/deep/.home_wrap_analysis {
// height: 89vh;
.home_form {
padding-bottom: 0px;
}
.form_item {
margin-bottom: 0 !important;
textarea {
// padding-top: 20px;
// height: 80vh !important;
}
.uni-textarea-wrapper {
// height: 100% !important;
}
textarea {
max-width: 100%;
width: 100%;
min-width: 100%;
height: calc(95vh - 200px) !important;
border: none;
}
.ql-container {
height: calc(95vh - 200px) !important;
border: none;
}
textarea:focus {
outline: none; /* 去除系统默认黑色描边 */
border: 1px solid #409eff; /* 可选:设置你希望的边框颜色 */
box-shadow: none; /* 可选:移除蓝色阴影(某些浏览器) */
}
}
}
.content_detail {
background: #fff;
}
.message_wrap_detail {
padding: 0;
}
.wordItem:nth-child(3n) {
margin-right: 0 !important;
}
</style>