feat(kg): 数据导入+规则库
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
package com.healthlink.his.web.knowledgegraph.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ImportResultDto {
|
||||
private int successCount;
|
||||
private int failCount;
|
||||
private int totalRows;
|
||||
private String message;
|
||||
}
|
||||
@@ -103,3 +103,43 @@ export function getPathwayPage(params) {
|
||||
export function getPathwaySteps(id) {
|
||||
return request({ url: `/knowledgegraph/pathway/${id}/steps`, method: 'get' })
|
||||
}
|
||||
|
||||
// KG3: 推理引擎
|
||||
export function suggestDiagnosis(data) {
|
||||
return request({ url: '/knowledgegraph/reasoning/diagnosis', method: 'post', data })
|
||||
}
|
||||
|
||||
export function suggestExaminations(data) {
|
||||
return request({ url: '/knowledgegraph/reasoning/examination', method: 'post', data })
|
||||
}
|
||||
|
||||
export function checkDrugInteractions(data) {
|
||||
return request({ url: '/knowledgegraph/reasoning/drug-interaction', method: 'post', data })
|
||||
}
|
||||
|
||||
export function suggestPathway(diseaseCode) {
|
||||
return request({ url: `/knowledgegraph/reasoning/pathway/${diseaseCode}`, method: 'get' })
|
||||
}
|
||||
|
||||
// KG4: 数据导入
|
||||
export function importDisease(file) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
return request({ url: '/knowledgegraph/import/disease', method: 'post', data: formData, headers: { 'Content-Type': 'multipart/form-data' } })
|
||||
}
|
||||
|
||||
export function importDrug(file) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
return request({ url: '/knowledgegraph/import/drug', method: 'post', data: formData, headers: { 'Content-Type': 'multipart/form-data' } })
|
||||
}
|
||||
|
||||
export function importRelations(file) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
return request({ url: '/knowledgegraph/import/relation', method: 'post', data: formData, headers: { 'Content-Type': 'multipart/form-data' } })
|
||||
}
|
||||
|
||||
export function downloadImportTemplate(type) {
|
||||
return request({ url: `/knowledgegraph/import/template/${type}`, method: 'get', responseType: 'blob' })
|
||||
}
|
||||
|
||||
134
healthlink-his-ui/src/views/knowledgegraph/DataImport.vue
Normal file
134
healthlink-his-ui/src/views/knowledgegraph/DataImport.vue
Normal file
@@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<span>知识图谱数据导入</span>
|
||||
</template>
|
||||
|
||||
<el-tabs v-model="activeTab">
|
||||
<el-tab-pane label="疾病导入" name="disease">
|
||||
<div class="import-section">
|
||||
<p class="tip">CSV格式:疾病编码,疾病名称,分类,科室,严重等级,描述,关键词</p>
|
||||
<el-upload ref="diseaseUpload" :auto-upload="false" :limit="1" accept=".csv" :on-change="(f) => handleFileChange(f, 'disease')" :on-remove="() => clearFile('disease')">
|
||||
<el-button type="primary">选择CSV文件</el-button>
|
||||
</el-upload>
|
||||
<div class="mt16">
|
||||
<el-button type="success" :loading="importing" :disabled="!files.disease" @click="doImport('disease')">开始导入</el-button>
|
||||
<el-button link type="primary" @click="downloadTemplate('disease')">下载模板</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="药物导入" name="drug">
|
||||
<div class="import-section">
|
||||
<p class="tip">CSV格式:药物编码,药物名称,通用名,分类,剂型,禁忌症,不良反应</p>
|
||||
<el-upload ref="drugUpload" :auto-upload="false" :limit="1" accept=".csv" :on-change="(f) => handleFileChange(f, 'drug')" :on-remove="() => clearFile('drug')">
|
||||
<el-button type="primary">选择CSV文件</el-button>
|
||||
</el-upload>
|
||||
<div class="mt16">
|
||||
<el-button type="success" :loading="importing" :disabled="!files.drug" @click="doImport('drug')">开始导入</el-button>
|
||||
<el-button link type="primary" @click="downloadTemplate('drug')">下载模板</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="关系导入" name="relation">
|
||||
<div class="import-section">
|
||||
<p class="tip">CSV格式:来源类型,来源ID,目标类型,目标ID,关系类型,关系强度,描述,证据来源</p>
|
||||
<el-upload ref="relationUpload" :auto-upload="false" :limit="1" accept=".csv" :on-change="(f) => handleFileChange(f, 'relation')" :on-remove="() => clearFile('relation')">
|
||||
<el-button type="primary">选择CSV文件</el-button>
|
||||
</el-upload>
|
||||
<div class="mt16">
|
||||
<el-button type="success" :loading="importing" :disabled="!files.relation" @click="doImport('relation')">开始导入</el-button>
|
||||
<el-button link type="primary" @click="downloadTemplate('relation')">下载模板</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mt16" v-if="importResult">
|
||||
<template #header>
|
||||
<span>导入结果</span>
|
||||
</template>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="总行数">{{ importResult.totalRows }}</el-descriptions-item>
|
||||
<el-descriptions-item label="成功">{{ importResult.successCount }}</el-descriptions-item>
|
||||
<el-descriptions-item label="失败">{{ importResult.failCount }}</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">
|
||||
<el-tag :type="importResult.failCount === 0 ? 'success' : 'warning'">
|
||||
{{ importResult.failCount === 0 ? '全部成功' : '部分失败' }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<p class="mt16">{{ importResult.message }}</p>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="KgDataImport">
|
||||
import { ref, reactive } from 'vue'
|
||||
import { importDisease, importDrug, importRelations, downloadImportTemplate } from '@/api/knowledgegraph/api'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const activeTab = ref('disease')
|
||||
const importing = ref(false)
|
||||
const importResult = ref(null)
|
||||
|
||||
const files = reactive({ disease: null, drug: null, relation: null })
|
||||
|
||||
function handleFileChange(file, type) {
|
||||
files[type] = file.raw
|
||||
}
|
||||
|
||||
function clearFile(type) {
|
||||
files[type] = null
|
||||
}
|
||||
|
||||
async function doImport(type) {
|
||||
const file = files[type]
|
||||
if (!file) {
|
||||
ElMessage.warning('请先选择文件')
|
||||
return
|
||||
}
|
||||
importing.value = true
|
||||
importResult.value = null
|
||||
try {
|
||||
let res
|
||||
if (type === 'disease') res = await importDisease(file)
|
||||
else if (type === 'drug') res = await importDrug(file)
|
||||
else res = await importRelations(file)
|
||||
|
||||
if (res.code === 200) {
|
||||
importResult.value = res.data
|
||||
ElMessage.success('导入完成')
|
||||
} else {
|
||||
ElMessage.error(res.msg || '导入失败')
|
||||
}
|
||||
} finally {
|
||||
importing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function downloadTemplate(type) {
|
||||
try {
|
||||
const res = await downloadImportTemplate(type)
|
||||
const blob = new Blob([res], { type: 'text/csv;charset=utf-8' })
|
||||
const url = window.URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
const names = { disease: '疾病导入模板', drug: '药物导入模板', relation: '关系导入模板' }
|
||||
link.download = names[type] + '.csv'
|
||||
link.click()
|
||||
window.URL.revokeObjectURL(url)
|
||||
} catch {
|
||||
ElMessage.error('下载模板失败')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mt16 { margin-top: 16px; }
|
||||
.tip { color: #909399; font-size: 13px; margin-bottom: 12px; }
|
||||
.import-section { padding: 12px 0; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user