以下子組件依上述修改:
<!-- mrdnrelate.vue -->
<template>
<div class="mrdnrelate-container">
<!-- 相关病态区域(上方) -->
<div class="tags-section">
<h3>尚未與此醫案關聯的病態列表</h3>
<div class="filter-info" v-if="filteredTags.length > 0">
顯示與當前醫案不同但相關的病態標籤({{ filteredTags.length }}個)
</div>
<div v-if="filteredTags.length > 0" class="dntag-list">
<div v-for="(tag, index) in filteredTags" :key="tag.id" class="dntag-item">
<div class="tag-content">
<span class="tag-index">{{ index + 1 }}.</span>
<span class="tag-name">{{ tag.id }}: {{ tag.dnname || '未命名標籤' }}</span>
</div>
</div>
</div>
<div v-else class="no-tags">
沒有符合條件的相關病態標籤
</div>
</div>
<!-- 分隔线 -->
<div class="divider"></div>
<!-- MRDN数据区域(下方) -->
<div class="mrdn-section">
<h3>醫案病態關聯管理</h3>
<!-- 操作按钮 -->
<div class="mrdn-controls">
<button @click="fetchMRDNData" class="refresh-btn">刷新數據</button>
<button @click="manualCreateMRDN" class="create-btn">手動新增關聯</button>
</div>
<!-- 数据列表 -->
<div v-if="mrdnData.length > 0" class="mrdn-list">
<table class="mrdn-table">
<thead>
<tr>
<th>ID</th>
<th>醫案ID</th>
<th>病態ID</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="item in mrdnData" :key="item.id">
<td>{{ item.id }}</td>
<td>
<span v-if="!item.editing">{{ item.mrinfo }}</span>
<textarea v-else v-model="item.editData.mrinfo" class="edit-textarea"></textarea>
</td>
<td>
<span v-if="!item.editing">{{ item.dntag }}</span>
<input v-else v-model="item.editData.dntag" type="text" class="edit-input">
</td>
<td class="actions">
<template v-if="!item.editing">
<button @click="startEdit(item)" class="edit-btn">編輯</button>
<button @click="confirmDelete(item.id)" class="delete-btn">刪除</button>
</template>
<template v-else>
<button @click="saveEdit(item)" class="save-btn">保存</button>
<button @click="cancelEdit(item)" class="cancel-btn">取消</button>
</template>
</td>
</tr>
</tbody>
</table>
</div>
<div v-else class="no-data">
沒有醫案病態關聯數據
</div>
</div>
</div>
</template>
<script>
import { secureFetch } from '../utils/request';
export default {
name: 'mrdnrelate',
props: {
currentCase: {
type: Object,
default: null
},
allTags: {
type: Array,
required: true
}
},
data() {
return {
mrdnData: [],
isCreating: false,
hasAutoCreated: false
};
},
computed: {
filteredTags() {
if (!this.currentCase) return [];
const currentTagIds = this.currentCase.dntag
? this.currentCase.dntag.map(tag => tag.id)
: [];
const caseContent = this.currentCase.mrcase || '';
const contentLower = caseContent.toLowerCase();
return this.allTags.filter(tag => {
if (currentTagIds.includes(tag.id)) return false;
if (!tag.dnname) return false;
return contentLower.includes(tag.dnname.toLowerCase());
});
}
},
watch: {
currentCase: {
immediate: true,
handler(newVal) {
if (newVal && newVal.id) {
// 确保自动创建逻辑执行
this.autoCreateMRDN();
}
}
}
},
methods: {
async fetchMRDNData() {
try {
const response = await fetch("MRDN/?format=json");
const data = await response.json();
this.mrdnData = data.map(item => ({
id: item.id,
mrinfo: item.mrinfo || '',
dntag: item.dntag || '',
editing: false,
editData: {
mrinfo: item.mrinfo || '',
dntag: item.dntag || ''
}
}));
} catch (error) {
console.error("獲取MRDN數據失敗:", error);
alert("MRDN數據加載失敗");
}
},
async autoCreateMRDN() {
if (this.isCreating) return;
if (!this.currentCase || !this.currentCase.id) return;
if (this.filteredTags.length === 0) return;
if (this.hasAutoCreated) return; // 防止重复执行
try {
this.isCreating = true;
const createRequests = this.filteredTags.map(tag => {
return secureFetch("MRDN/", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": this.getCSRFToken()
},
body: JSON.stringify({
mrinfo: `${this.currentCase.id}`,
dntag: `${tag.id}`
})
});
});
const responses = await Promise.all(createRequests);
const allSuccess = responses.every(res => res.ok);
if (allSuccess) {
console.log(`成功新增 ${this.filteredTags.length} 筆MRDN數據!`);
this.fetchMRDNData();
this.triggerDataUpdate();
this.hasAutoCreated = true; // 标记已执行
} else {
throw new Error("部分新增失敗");
}
} catch (error) {
console.error("批量新增MRDN失敗:", error);
alert("自動新增關聯時發生錯誤");
} finally {
this.isCreating = false;
}
},
async manualCreateMRDN() {
try {
await this.autoCreateMRDN();
if (this.filteredTags.length > 0) {
alert(`成功新增 ${this.filteredTags.length} 筆MRDN數據!`);
}
} catch (error) {
alert("新增過程中發生錯誤");
}
},
startEdit(item) {
item.editing = true;
item.editData = {
mrinfo: item.mrinfo,
dntag: item.dntag
};
},
cancelEdit(item) {
item.editing = false;
},
async saveEdit(item) {
try {
const response = await secureFetch(`MRDN/${item.id}/`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": this.getCSRFToken()
},
body: JSON.stringify({
mrinfo: item.editData.mrinfo,
dntag: item.editData.dntag
})
});
if (response.ok) {
item.mrinfo = item.editData.mrinfo;
item.dntag = item.editData.dntag;
item.editing = false;
alert("更新成功!");
this.triggerDataUpdate();
} else {
throw new Error("更新失敗");
}
} catch (error) {
console.error("更新MRDN失敗:", error);
alert("更新失敗");
}
},
confirmDelete(id) {
if (confirm("確定要刪除此數據嗎?")) {
this.deleteMRDN(id);
}
},
async deleteMRDN(id) {
try {
const response = await secureFetch(`MRDN/${id}/`, {
method: "DELETE",
headers: {
"X-CSRFToken": this.getCSRFToken()
}
});
if (response.ok) {
this.mrdnData = this.mrdnData.filter(item => item.id !== id);
alert("刪除成功!");
this.triggerDataUpdate();
} else {
throw new Error("刪除失敗");
}
} catch (error) {
console.error("刪除MRDN失敗:", error);
alert("刪除失敗");
}
},
getCSRFToken() {
return document.querySelector('[name=csrfmiddlewaretoken]')?.value || '';
},
triggerDataUpdate() {
this.$emit('data-updated');
}
},
mounted() {
// 确保自动执行刷新数据和新增关联
this.fetchMRDNData();
if (this.currentCase && this.currentCase.id) {
this.autoCreateMRDN();
}
}
};
</script>
<style scoped>
.mrdnrelate-container {
padding: 15px;
background: #FFE0B2; /* 浅蓝色 -> 浅橙色 */
height: 100%;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 15px;
}
.tags-section {
flex: 0 0 40%;
overflow-y: auto;
background: rgba(255, 255, 255, 0.3);
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.divider {
height: 2px;
background: #FF9800; /* 蓝色 -> 橙色 */
margin: 10px 0;
}
.mrdn-section {
flex: 1;
overflow-y: auto;
background: rgba(255, 255, 255, 0.3);
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
h3 {
margin-top: 0;
padding-bottom: 8px;
color: #2c3e50;
text-align: center;
border-bottom: 2px solid #FF9800; /* 蓝色 -> 橙色 */
}
.filter-info {
text-align: center;
margin: 10px 0;
font-size: 0.9em;
color: #555;
background: rgba(255, 255, 255, 0.3);
padding: 5px;
border-radius: 4px;
}
.dntag-list {
display: grid;
grid-template-columns: 1fr;
gap: 12px;
margin-top: 15px;
}
.dntag-item {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
overflow: hidden;
transition: all 0.3s ease;
border-left: 4px solid #FF9800; /* 蓝色 -> 橙色 */
}
.tag-content {
padding: 12px 15px;
display: flex;
align-items: center;
}
.tag-index {
font-weight: bold;
margin-right: 10px;
min-width: 25px;
height: 25px;
display: flex;
align-items: center;
justify-content: center;
background: #FF9800; /* 蓝色 -> 橙色 */
color: white;
border-radius: 50%;
}
.tag-name {
flex-grow: 1;
font-weight: 500;
color: #2c3e50;
}
.no-tags, .no-data {
padding: 25px;
text-align: center;
color: #666;
font-style: italic;
margin-top: 20px;
border: 1px dashed #FF9800; /* 蓝色 -> 橙色 */
border-radius: 8px;
background: rgba(255, 255, 255, 0.5);
}
/* MRDN数据管理样式 */
.mrdn-controls {
display: flex;
justify-content: space-between;
margin-bottom: 15px;
}
.mrdn-controls button {
padding: 6px 12px;
border-radius: 4px;
border: none;
cursor: pointer;
font-weight: bold;
}
.refresh-btn {
background-color: #4CAF50;
color: white;
}
.create-btn {
background-color: #FF9800; /* 蓝色 -> 橙色 */
color: white;
}
.mrdn-table {
width: 100%;
border-collapse: collapse;
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.mrdn-table th, .mrdn-table td {
padding: 12px 15px;
text-align: left;
border-bottom: 1px solid #eee;
}
.mrdn-table th {
background-color: #FF9800; /* 蓝色 -> 橙色 */
color: white;
font-weight: bold;
}
.mrdn-table tr:hover {
background-color: #f5f5f5;
}
.actions {
display: flex;
gap: 5px;
}
.actions button {
padding: 5px 10px;
border: none;
border-radius: 3px;
cursor: pointer;
font-size: 0.85em;
}
.edit-btn {
background-color: #FFC107;
color: #333;
}
.delete-btn {
background-color: #F44336;
color: white;
}
.save-btn {
background-color: #4CAF50;
color: white;
}
.cancel-btn {
background-color: #9E9E9E;
color: white;
}
.edit-input, .edit-textarea {
width: 100%;
padding: 5px;
border: 1px solid #ddd;
border-radius: 3px;
}
.edit-textarea {
min-height: 60px;
resize: vertical;
}
</style>
最新发布