以下mreditor.vue代碼頁面獲得json資料時,將位於MRInfo/?format=json中mrcase字段內的字串與,另一個位於DNTag/?format=json的drf api中字段為dnname內的字串比對,mrcase欄位中與dnname欄位找到相同的字串時,獲取其在DNTag/?format=json中的dntag的id與原位於MRInfo/?format=json中mrinfo的id,然後將此dntag id與mrinfo id到MRDN/?format=json與獲取的json資料比對,若dntag id與mrinfo id在與MRDN/?format=json與獲取的json資料比對后顯示為已建立關聯的json資料,則不做任何動作,若無建立關連,則在MRDN/?format=json的位置以post方法建立dntag id與mrinfo id關聯的json資料:
mreditor.vue代碼:
<template>
<div>
<div>
<div class="wangeditor">
<WangEditor v-model="content" @response="(msg) => content = msg" />
</div>
<div class="right-panel">
<!-- 病态名称显示区域 -->
<div class="dntag-display" v-if="currentDnTags.length">
<div class="field-name">病態名稱:</div>
<div class="dntag-value">{{ currentDnTags.join(';') }}</div>
</div>
<div class="dntag-display" v-else>
<div class="field-name">病態名稱:</div>
<div class="dntag-value">無關聯病態名稱</div>
</div>
<mreditor1 ref="mreditor1" />
</div>
</div>
<div class="tag-panel">
<!-- 病态编辑面板 -->
<mrdncrud v-if="showDnCrud" @tag-updated="handleTagUpdated" />
</div>
<div class="content-display" v-html="displayContent"></div>
<footer class="sticky-footer">
<span><button @click="toggleDisplayFormat">{{ displayButtonText }}</button></span>
<span><button @click="resetAll" class="reset-btn">輸入新醫案</button></span>
<!-- 新增病态编辑切换按钮 -->
<span>
<button @click="toggleDnCrud" class="dncrud-btn">
{{ showDnCrud ? '隱藏病態編輯' : '編輯病態' }}
</button>
</span>
<span class="id-input">
<input v-model="fetchId" placeholder="輸入醫案ID" type="number" min="1" />
<button @click="fetchById">載入醫案</button>
</span>
<span v-if="submittedId">
<button @click="updateContent" class="update-btn">更新醫案</button>
<button @click="deleteContent" class="delete-btn">刪除醫案</button>
</span>
<span v-else>
<button @click="submitContent" class="submit-btn">提交醫案</button>
</span>
<span v-if="submittedId" class="submitted-id">醫案 ID: {{ submittedId }}</span>
<span>醫案編輯器</span>
</footer>
</div>
</template>
<script>
import WangEditor from './WangEditor.vue';
import mreditor1 from './mreditor1.vue';
import mrdncrud from './mrdncrud.vue'; // 导入病态编辑组件
import LZString from 'lz-string';
export default {
name: 'mreditor',
components: {
WangEditor,
mreditor1,
mrdncrud
},
data() {
return {
content: '',
submittedId: null,
fetchId: null,
dnTags: [],
showRawHtml: false,
stateVersion: '1.0',
autoSaveTimer: null,
autoSaveInterval: 30000,
currentDnTags: [], // 存储当前医案的病态名称
dnTagMap: {}, // 标签ID到名称的映射
showDnCrud: false // 控制病态编辑面板显示
};
},
computed: {
highlightedContent() {
if (!this.dnTags.length || !this.content) return this.content;
const tempEl = document.createElement('div');
tempEl.innerHTML = this.content;
const walker = document.createTreeWalker(
tempEl,
NodeFilter.SHOW_TEXT
);
const nodes = [];
while (walker.nextNode()) {
nodes.push(walker.currentNode);
}
nodes.forEach(node => {
let text = node.nodeValue;
let newHtml = text;
this.dnTags
.slice()
.sort((a, b) => b.length - a.length)
.forEach(tag => {
const regex = new RegExp(
this.escapeRegExp(tag),
'g'
);
newHtml = newHtml.replace(
regex,
`<span style="color: rgb(212, 107, 8); font-weight: bold;">${tag}</span>`
);
});
if (newHtml !== text) {
const span = document.createElement('span');
span.innerHTML = newHtml;
node.parentNode.replaceChild(span, node);
}
});
return tempEl.innerHTML;
},
displayContent() {
if (this.showRawHtml) {
return this.escapeHtml(this.content);
}
return this.highlightedContent;
},
displayButtonText() {
return this.showRawHtml ? '顯示渲染格式' : '顯示原始標籤';
}
},
watch: {
content: {
handler() {
this.debouncedSaveState();
},
deep: true
}
},
async mounted() {
await this.fetchDNTags();
this.restoreState();
this.setupAutoSave();
},
activated() {
console.log('醫案編輯器被激活');
this.restoreState();
this.setupAutoSave();
},
deactivated() {
console.log('醫案編輯器被停用');
this.saveState();
this.clearAutoSave();
},
beforeDestroy() {
this.clearAutoSave();
},
methods: {
// 切换病态编辑面板显示
toggleDnCrud() {
this.showDnCrud = !this.showDnCrud;
if (this.showDnCrud) {
// 调整布局以显示编辑面板
document.querySelector('.tag-panel').style.display = 'block';
} else {
document.querySelector('.tag-panel').style.display = 'none';
}
},
// 处理标签更新事件
handleTagUpdated() {
console.log('病态标签已更新,刷新数据');
this.fetchDNTags(); // 刷新标签数据
},
escapeHtml(unsafe) {
if (!unsafe) return '';
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
},
escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
},
setupAutoSave() {
this.clearAutoSave();
this.autoSaveTimer = setInterval(() => {
if (this.content || this.submittedId) {
console.log('自动保存状态...');
this.saveState();
}
}, this.autoSaveInterval);
},
clearAutoSave() {
if (this.autoSaveTimer) {
clearInterval(this.autoSaveTimer);
this.autoSaveTimer = null;
}
},
debouncedSaveState() {
this.clearAutoSave();
this.autoSaveTimer = setTimeout(() => {
this.saveState();
this.setupAutoSave();
}, 2000);
},
saveState() {
const formData = this.$refs.mreditor1 ? this.$refs.mreditor1.getFormData() : { };
const state = {
version: this.stateVersion,
content: this.content,
submittedId: this.submittedId,
formData: formData,
showRawHtml: this.showRawHtml,
currentDnTags: this.currentDnTags, // 保存病态名称
timestamp: new Date().getTime()
};
if (this.content.length > 2000) {
try {
state.compressed = true;
state.content = LZString.compressToUTF16(this.content);
} catch (e) {
console.error('压缩失败,使用原始数据', e);
state.compressed = false;
}
}
sessionStorage.setItem('medicalRecordState', JSON.stringify(state));
},
restoreState() {
const savedState = sessionStorage.getItem('medicalRecordState');
if (!savedState) return;
try {
const state = JSON.parse(savedState);
if (state.version !== this.stateVersion) {
console.warn('状态版本不匹配,跳过恢复');
return;
}
let content = state.content;
if (state.compressed) {
try {
content = LZString.decompressFromUTF16(content);
} catch (e) {
console.error('解压失败,使用原始数据', e);
}
}
this.content = content;
this.submittedId = state.submittedId;
this.showRawHtml = state.showRawHtml;
this.currentDnTags = state.currentDnTags || []; // 恢复病态名称
if (this.$refs.mreditor1 && state.formData) {
this.$refs.mreditor1.setFormData(state.formData);
}
console.log('医案状态已恢复');
} catch (e) {
console.error('状态恢复失败', e);
sessionStorage.removeItem('medicalRecordState');
}
},
clearState() {
sessionStorage.removeItem('medicalRecordState');
},
toggleDisplayFormat() {
this.showRawHtml = !this.showRawHtml;
this.saveState();
},
async fetchDNTags() {
try {
const response = await fetch('DNTag/?format=json');
const data = await response.json();
this.dnTags = data
.map(item => item.dnname)
.filter(name => name && name.trim().length > 0);
// 构建ID到名称的映射
this.dnTagMap = {};
data.forEach(item => {
if (item.id && item.dnname) {
this.dnTagMap[item.id] = item.dnname;
}
});
} catch (error) {
console.error('获取标签失败:', error);
alert('标签数据加载失败,高亮功能不可用');
}
},
async fetchById() {
if (!this.fetchId) {
alert('請輸入有效的醫案ID');
return;
}
try {
const response = await fetch(`MRInfo/${this.fetchId}/?format=json`);
if (response.ok) {
const data = await response.json();
if (this.$refs.mreditor1) {
this.$refs.mreditor1.formData.mrname = data.mrname || '';
this.$refs.mreditor1.formData.mrposter = data.mrposter || '';
}
this.content = data.mrcase || '';
this.submittedId = data.id;
this.fetchId = null;
// 处理病态名称显示
if (data.dntag && Array.isArray(data.dntag)) {
this.currentDnTags = data.dntag.map(id =>
this.dnTagMap[id] || `未知標籤(${id})`
);
} else {
this.currentDnTags = [];
}
await this.fetchDNTags();
this.saveState();
alert('醫案數據加載成功!');
} else if (response.status === 404) {
alert('未找到該ID的醫案');
} else {
throw new Error('獲取醫案失敗');
}
} catch (error) {
console.error('Error:', error);
alert(`獲取醫案失敗: ${error.message}`);
}
},
async submitContent() {
if (!this.$refs.mreditor1) return;
const formData = this.$refs.mreditor1.getFormData();
const postData = {
mrcase: this.content,
...formData
};
try {
const response = await fetch('MRInfo/?format=json', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(postData),
});
if (response.ok) {
const data = await response.json();
this.submittedId = data.id;
// 处理返回的病态名称
if (data.dntag && Array.isArray(data.dntag)) {
this.currentDnTags = data.dntag.map(id =>
this.dnTagMap[id] || `未知標籤(${id})`
);
} else {
this.currentDnTags = [];
}
this.saveState();
alert('醫案提交成功!');
} else {
throw new Error('提交失败');
}
} catch (error) {
console.error('Error:', error);
alert(`提交失败: ${error.message}`);
}
},
async updateContent() {
if (!this.submittedId || !this.$refs.mreditor1) return;
const formData = this.$refs.mreditor1.getFormData();
const postData = {
mrcase: this.content,
...formData
};
try {
const response = await fetch(`MRInfo/${this.submittedId}/?format=json`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(postData),
});
if (response.ok) {
const data = await response.json();
// 更新病态名称显示
if (data.dntag && Array.isArray(data.dntag)) {
this.currentDnTags = data.dntag.map(id =>
this.dnTagMap[id] || `未知標籤(${id})`
);
}
this.saveState();
alert('醫案更新成功!');
} else {
throw new Error('更新失败');
}
} catch (error) {
console.error('Error:', error);
alert(`更新失败: ${error.message}`);
}
},
async deleteContent() {
if (!this.submittedId) return;
if (!confirm('確定要刪除這個醫案嗎?')) return;
try {
const response = await fetch(`MRInfo/${this.submittedId}/?format=json`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
}
});
if (response.ok) {
this.clearState();
this.resetAll();
alert('醫案刪除成功!');
} else {
throw new Error('刪除失败');
}
} catch (error) {
console.error('Error:', error);
alert(`刪除失败: ${error.message}`);
}
},
resetAll() {
this.content = '';
this.submittedId = null;
this.fetchId = null;
this.showRawHtml = false;
this.currentDnTags = []; // 重置病态名称
this.showDnCrud = false; // 隐藏病态编辑面板
if (this.$refs.mreditor1) {
this.$refs.mreditor1.resetForm();
}
this.clearState();
// 确保隐藏编辑面板
document.querySelector('.tag-panel').style.display = 'none';
}
}
};
</script>
<style scoped>
.wangeditor {
flex: 1;
padding: 10px;
overflow-y: auto;
}
.right-panel {
position: fixed;
top: 55px;
bottom: 45px;
right: 0;
width: 30%;
background: lightblue;
padding: 1px;
z-index: 100;
overflow-y: auto;
}
/* 病态名称显示样式 */
.dntag-display {
display: flex;
margin-top: 1px;
padding: 10px;
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
.field-name {
font-weight: bold;
min-width: 80px;
color: #495057;
font-size: 1rem;
}
.dntag-value {
flex-grow: 1;
color: #212529;
font-weight: 500;
padding-left: 10px;
border-left: 2px solid #ffc107;
}
.tag-panel {
position: fixed;
top: 400px;
bottom: 45px;
right: 0;
width: 30%;
background: lightyellow;
padding: 10px;
z-index: 100;
overflow-y: auto;
display: none; /*默认隐藏 */
}
.content-display {
position: fixed;
top: 490px;
left: 0;
width: 70%;
bottom: 45px;
z-index: 999;
background-color: white;
overflow-y: auto;
padding: 10px;
border: 1px solid #eee;
white-space: pre-wrap;
}
.sticky-footer {
display: flex;
justify-content: flex-end;
align-items: center;
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background-color: #ffd800ff;
z-index: 999;
padding: 10px 20px;
box-sizing: border-box;
flex-wrap: wrap;
}
.sticky-footer > span {
margin-left: 5px;
display: flex;
align-items: center;
}
/* 新增病态编辑按钮样式 */
.dncrud-btn {
background-color: #9c27b0;
color: white;
border: none;
padding: 2px 8px;
border-radius: 4px;
cursor: pointer;
margin-left: 10px;
}
.dncrud-btn:hover {
background-color: #7b1fa2;
}
.submitted-id {
padding: 2px;
background-color: #e2f0fd;
color: #004085;
border-radius: 4px;
}
.reset-btn {
margin-left: 10px;
padding: 2px;
background-color: #dc3545;
border: none;
color: white;
border-radius: 4px;
cursor: pointer;
}
.reset-btn:hover {
background-color: #c82333;
}
.id-input {
display: flex;
align-items: center;
}
.id-input input {
width: 100px;
padding: 2px 5px;
margin-right: 5px;
border: 1px solid #ccc;
border-radius: 4px;
}
.submit-btn {
background-color: #28a745;
color: white;
border: none;
padding: 2px 8px;
border-radius: 4px;
cursor: pointer;
}
.update-btn {
background-color: #007bff;
color: white;
border: none;
padding: 2px 8px;
border-radius: 4px;
cursor: pointer;
}
.delete-btn {
background-color: #dc3545;
color: white;
border: none;
padding: 2px 8px;
border-radius: 4px;
cursor: pointer;
}
.submit-btn:hover {
background-color: #218838;
}
.update-btn:hover {
background-color: #0069d9;
}
.delete-btn:hover {
background-color: #c82333;
}
</style>
最新发布