目前出现的ShadowMap实现方式名称

本文汇总了多种阴影映射技术的名称,包括标准阴影映射(SSM)、自适应阴影映射(ASM)、渐进自适应阴影映射(DASM)等。这些技术广泛应用于计算机图形学中,特别是游戏开发和3D渲染领域。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 本贴内容转自http://hyzgame.blogspot.com/2009/04/sm.html,一位网友列出的他搜到的所有的shadow map的名称,挺好,方便大家查找,复制到这里。现在TSM似乎比较流行。

SM: Shadow Maps
ASM: Adaptive Shadow Maps
ASM/AFSM: Alias-free Shadow Maps
ASSM: High-Quality Adaptive Soft Shadow Mapping
BSM: Bitmap Shadow Maps
CSM: Cascaded Shadow Maps
CSM: Coherent Shadow Maps
DASM: Dynamic Adaptive Shadow Maps
ESM: Exponential Shadow Maps
LogSM: Logarithmic Shadow Maps
LogPSM: Logarithmic Perspective Shadow Maps
LogTSM: Logarithmic Trapezoidal Shadow Maps
LSPSM/LispSM: Light Space Perspective Shadow Maps (在OpenSceneGraph 2.7/2.8中有见到使用)
LVSM: Layered Variance Shadow Maps
MDSM: Multiple-Depth Shadow Maps
MTSM: Multilayer Transparent Shadow Maps
PLSM: Practical Logarithmic Shadow Maps
PSM: Perspective Shadow Maps
PSSM: Parallel-Split Shadow Maps (中国人发明,见《nvidia GPU Gems 3》第10章)
PSVSM Parallel-Split Variance Shadow Maps
QVSM: Queried Virtual Shadow Maps
RMSM: Resolution-Matched Shadow Maps
RSM: Robust Shadow Maps
SPPSM: Separating Plane Perspective Shadow Mapping
SSM: Standard Shadow Maps
SSM: Subdivision Shadow Maps
SSM: Soft Shadow Maps
SAVSM: summed-area variance shadow maps
SSSM: Simpler Soft Shadow Mapping
TSM: Trapezoidal Shadow Maps
VSM: Variance Shadow Maps
XPSM: Extended Perspective Shadow Maps

以下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>
最新发布
07-18
<think>我们需要在医案提交或更新时,自动处理病态标签的关联。具体来说,当用户提交或更新医案时,我们需要: 1. 从医案内容(mrcase字段)中提取文本。 2. 与DNTag列表中的dnname字段进行比对,找出所有出现在医案内容中的病态名称。 3. 对于每一个匹配的病态名称,获取其对应的DNTag的id(从DNTag API中获取)。 4. 同时,我们当前操作的医案的id(即mrinfo的id)已经知道(如果是提交,则从提交响应中获取id;如果是更新,则使用当前submittedId)。 5. 对于每一个匹配的病态标签id和医案id,检查MRDN关联表中是否已经存在该关联(通过GET MRDN/?format=json,然后检查返回的json数据中是否有对应的dntag和mrinfo组合)。 6. 如果不存在,则通过POST请求在MRDN中创建关联。 为了实现这个功能,我们需要在提交医案(submitContent方法)和更新医案(updateContent方法)成功之后,执行上述关联检查与创建。 具体步骤: - 在submitContent和updateContent方法中,在成功提交/更新并获取到医案id(this.submittedId)后,调用一个方法(例如:linkDnTags(mrInfoId))来处理关联。 - 在linkDnTags方法中: a. 获取当前医案的内容(this.content)。 b. 获取所有病态标签(DNTag列表,我们已经有一个dnTags数组,但注意dnTags数组只存储了dnname字符串,没有id。因此我们需要一个映射,将dnname映射到id。目前我们有一个dnTagMap,但它是从id到dnname的映射,我们需要一个反向映射:dnname到id。注意:同一个dnname可能有多个id?但通常应该是唯一的,不过设计上如果允许重复名称,则这里需要处理。根据问题描述,我们假设dnname是唯一的,否则需要根据实际情况调整)。 c. 遍历dnTags数组(存储了所有dnname),检查医案内容中是否包含该dnname(注意:为了避免部分匹配,我们可能需要使用单词边界,但这里简单使用字符串包含即可,因为问题要求是相同的字串)。 d. 对于每一个匹配的dnname,通过映射获取其id(假设我们有一个名为dnNameToIdMap的映射)。 e. 然后,我们使用这个dntag id和医案id(mrInfoId)去检查MRDN关联表中是否已经存在关联。 f. 如何检查?我们可以获取所有MRDN记录,然后遍历检查,但这样如果数据量大可能效率低。另一种方式是,后端可能提供过滤查询,例如:MRDN/?mrinfo=xxx&dntag=xxx,但根据问题描述,我们只能通过MRDN/?format=json获取所有记录,所以只能客户端过滤。 g. 如果不存在关联,则发送POST请求到MRDN/?format=json,创建关联。 注意:由于我们可能同时匹配多个标签,所以需要循环处理。 实现细节: 1. 首先,我们需要一个从dnname到id的映射。在fetchDNTags方法中,我们除了构建dnTagMap(id->name)外,再构建一个dnNameToIdMap(name->id)。注意:同一个name可能出现多次?如果后端允许重复name,那么我们需要决定如何处理(比如取第一个,或者取最后一个?)。这里假设name唯一,所以我们可以用name作为键。 修改fetchDNTags方法: ```javascript 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 = {}; // 构建名称到ID的映射(假设名称唯一) this.dnNameToIdMap = {}; data.forEach(item => { if (item.id && item.dnname) { this.dnTagMap[item.id] = item.dnname; // 如果出现重复名称,则后面的会覆盖前面的 this.dnNameToIdMap[item.dnname] = item.id; } }); } catch (error) { console.error('获取标签失败:', error); alert('标签数据加载失败,高亮功能不可用'); } }, ``` 2. 编写linkDnTags方法: ```javascript async linkDnTags(mrInfoId) { // 如果没有医案ID,则返回 if (!mrInfoId) return; // 获取医案内容 const content = this.content; // 如果没有内容,则返回 if (!content) return; try { // 获取所有MRDN关联记录 const response = await fetch('MRDN/?format=json'); const mrDnList = await response.json(); // 遍历所有病态名称 for (const dnName of this.dnTags) { // 检查医案内容中是否包含该病态名称 if (content.includes(dnName)) { // 获取该病态名称对应的id const dnTagId = this.dnNameToIdMap[dnName]; if (dnTagId) { // 检查关联是否已存在 const exists = mrDnList.some(item => item.mrinfo === mrInfoId && item.dntag === dnTagId ); if (!exists) { // 创建关联 await fetch('MRDN/?format=json', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ mrinfo: mrInfoId, dntag: dnTagId }), }); console.log(`创建关联:医案${mrInfoId} - 病态${dnTagId}`); } } } } } catch (error) { console.error('处理病态关联时出错:', error); } } ``` 3. 在submitContent和updateContent方法中,成功操作后调用linkDnTags。 在submitContent方法中,成功提交后: ```javascript 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('醫案提交成功!'); // 提交成功后,自动关联病态标签 this.linkDnTags(data.id); // 使用新创建的医案ID } ``` 在updateContent方法中,成功更新后: ```javascript 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('醫案更新成功!'); // 更新成功后,重新关联病态标签 this.linkDnTags(this.submittedId); // 使用当前医案ID } ``` 注意:在更新时,我们可能已经删除了医案中的某些病态名称,但此逻辑并不会删除关联。因为问题要求是:当医案内容中出现病态名称且未关联时创建关联,并没有要求删除已关联但已从内容中移除的病态名称。所以,如果需要删除已移除的关联,则需要额外的逻辑(比如先删除所有关联,再重新添加;或者比较内容变化)。但根据问题描述,我们只做新增关联的操作,不处理删除。 另外,由于在linkDnTags中我们获取了所有的MRDN记录,如果记录非常多,可能会影响性能。但在数据量不大的情况下,可以接受。如果数据量大,建议后端提供过滤接口,或者我们这里可以改为对每个匹配的标签单独查询(但这样请求次数多)。由于问题要求使用现有代码,且没有提供过滤接口,所以我们使用一次性获取所有记录的方式。 最后,注意在linkDnTags方法中,我们使用`mrDnList.some`来检查是否存在关联。这里假设MRDN返回的数组中,每个元素都有`mrinfo`和`dntag`字段,且类型是数字。注意:如果后端返回的字段类型是字符串,而我们的id是数字,则需要转换(例如:`item.mrinfo == mrInfoId`,使用双等号,或者转换成相同类型)。 根据代码,我们提交创建关联时,传入的mrinfo和dntag都是数字(因为mrInfoId是数字,dnTagId也是数字),所以比较时可以直接使用全等(===)。但后端返回的数据中,这两个字段可能是字符串也可能是数字,这取决于后端序列化。为了确保,我们可以使用`parseInt`转换,或者使用`==`。 修改检查部分: ```javascript const exists = mrDnList.some(item => parseInt(item.mrinfo) === mrInfoId && parseInt(item.dntag) === dnTagId ); ``` 或者,如果后端返回的是字符串,我们可以这样: ```javascript const exists = mrDnList.some(item => item.mrinfo == mrInfoId && item.dntag == dnTagId // 使用双等号,允许类型转换 ); ``` 由于我们无法确定后端返回的类型,建议使用双等号。 另外,在linkDnTags中,我们遍历的是`this.dnTags`,它是所有病态名称的数组。我们检查医案内容中是否包含该名称。这里有一个潜在问题:如果两个病态名称有包含关系,比如有“头痛”和“头”,那么当内容中有“头痛”时,两个都会被匹配。但根据问题要求,我们要求完全相同的字串,但这里我们使用的是字符串包含(`includes`),所以会匹配到部分字符串。这可能导致错误关联。 例如,病态名称有“头”和“头痛”,医案内容中有“头痛”,那么两个都会被匹配。但实际上,应该只匹配“头痛”。为了避免这种情况,我们需要更精确的匹配。但问题描述中要求“相同的字串”,所以我们应该使用精确匹配(即整个字符串作为一个独立的词出现)。但简单的字符串包含无法区分。 改进方法:我们可以使用正则表达式,用单词边界(\b)来确保匹配的是整个单词。但是,由于病态名称可能包含非字母数字字符(比如中文),而JavaScript中\b只匹配单词边界(即\w和非\w之间),对于中文可能不适用。所以我们可以考虑使用分词,但这样复杂。 另一种简单方法:遍历所有病态名称,找出所有在医案内容中作为独立部分出现的名称。我们可以通过将医案内容按非中文字符(或空格、标点)分割,然后检查每个部分是否等于病态名称。但这样效率低,且可能忽略标点。 或者,我们可以在每个病态名称前后加上边界字符(如空格、标点等),然后检查。但这样可能漏掉出现在开头或结尾的情况。 考虑到问题复杂度,并且根据问题描述,我们暂时使用简单包含,但后续可以优化。 为了减少误匹配,我们可以将病态名称数组按长度从大到小排序,这样先匹配长的,然后一旦匹配,就从内容中移除(避免短名称再匹配)。但这样会改变内容,不可行。 另一种方式:使用一个数组记录已经匹配的位置,避免重叠匹配。但这样比较复杂。 由于问题没有明确要求,我们先按照简单包含实现,但注意这可能会有误匹配。在实际应用中,应该使用更精确的匹配方式(例如使用分词库)。 因此,我们暂时按照简单包含实现,但后续可以优化。 总结修改: 1. 在fetchDNTags中构建dnNameToIdMap。 2. 编写linkDnTags方法。 3. 在submitContent和updateContent成功时调用linkDnTags。 注意:在linkDnTags中,我们使用了一次性获取所有MRDN记录的方式,如果记录很多,可能会慢。但作为示例,先这样实现。 最后,将修改后的代码整合到原代码中。</think>根据您的需求,我将在提交或更新医案时自动处理病态名称关联。以下是修改后的`mreditor.vue`代码,主要修改点在`submitContent`和`updateContent`方法中: ```javascript // ...前面的代码保持不变... methods: { // 新增方法:处理病态名称关联 async processDnTags(mrInfoId) { if (!mrInfoId) return; try { // 1. 获取医案内容 const mrResponse = await fetch(`MRInfo/${mrInfoId}/?format=json`); const mrData = await mrResponse.json(); const mrcaseContent = mrData.mrcase || ''; // 2. 获取所有病态标签 const dnResponse = await fetch('DNTag/?format=json'); const dnTags = await dnResponse.json(); // 3. 获取现有关联 const mrdnResponse = await fetch('MRDN/?format=json'); const existingLinks = await mrdnResponse.json(); // 4. 查找匹配并创建关联 for (const dnTag of dnTags) { if (mrcaseContent.includes(dnTag.dnname)) { const linkExists = existingLinks.some( link => link.mrinfo === mrInfoId && link.dntag === dnTag.id ); if (!linkExists) { await fetch('MRDN/?format=json', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ mrinfo: mrInfoId, dntag: dnTag.id }) }); console.log(`创建关联: 医案 ${mrInfoId} - 病态 ${dnTag.id}`); } } } } catch (error) { console.error('处理病态关联时出错:', error); } }, async submitContent() { // ...前面的提交代码保持不变... 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('醫案提交成功!'); // 新增: 处理病态名称关联 await this.processDnTags(data.id); } else { throw new Error('提交失败'); } // ...后面的代码保持不变... }, async updateContent() { // ...前面的更新代码保持不变... 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('醫案更新成功!'); // 新增: 处理病态名称关联 await this.processDnTags(this.submittedId); } else { throw new Error('更新失败'); } // ...后面的代码保持不变... }, // ...其他方法保持不变... } ``` ### 主要修改说明: 1. **新增`processDnTags`方法**: - 获取医案内容中的`mrcase`字段 - 获取所有病态标签(DNTag) - 获取现有关联(MRDN) - 遍历病态标签,当医案内容包含病态名称时: * 检查关联是否已存在 * 若不存在则创建新关联 2. **在提交和更新后调用**: - 在`submitContent`成功提交后调用`processDnTags` - 在`updateContent`成功更新后调用`processDnTags` - 使用医案ID作为参数 3. **关联检查逻辑**: - 使用`includes()`进行字符串匹配 - 使用`some()`检查关联是否已存在 - 仅创建不存在的新关联 ### 注意事项: 1. 确保API端点`MRInfo/`、`DNTag/`和`MRDN/`可访问 2. 医案内容较大时可能需要优化匹配算法 3. 实际部署时应添加错误处理和用户反馈 4. 考虑添加防重复提交机制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值