feat(emr): 打通EMR管理模块与门诊/住院病历集成
- 修复revision-history API路径与后端对齐 - EMR管理页面支持URL参数自动加载 - 医生工作站添加修订历史/完整性检查入口 - 住院医生工作站添加修订历史/完整性检查入口
This commit is contained in:
@@ -30,6 +30,22 @@
|
|||||||
>
|
>
|
||||||
历史病历
|
历史病历
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="info"
|
||||||
|
plain
|
||||||
|
style="margin-left: 20px"
|
||||||
|
@click="viewRevisionHistory()"
|
||||||
|
>
|
||||||
|
修订历史
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="info"
|
||||||
|
plain
|
||||||
|
style="margin-left: 20px"
|
||||||
|
@click="checkCompleteness()"
|
||||||
|
>
|
||||||
|
完整性检查
|
||||||
|
</el-button>
|
||||||
<!-- 可选:添加打印按钮 -->
|
<!-- 可选:添加打印按钮 -->
|
||||||
<!-- <el-button type="primary" plain @click="printEmr" style="margin-left: 20px">
|
<!-- <el-button type="primary" plain @click="printEmr" style="margin-left: 20px">
|
||||||
打印病历
|
打印病历
|
||||||
@@ -196,10 +212,13 @@
|
|||||||
import {getEmrDetail, saveEmr, saveEmrTemplate} from '../api';
|
import {getEmrDetail, saveEmr, saveEmrTemplate} from '../api';
|
||||||
import emrTemplate from '../emr/emrtemplate.vue';
|
import emrTemplate from '../emr/emrtemplate.vue';
|
||||||
import emrhistory from '../emr/emrhistory.vue';
|
import emrhistory from '../emr/emrhistory.vue';
|
||||||
|
import {checkCompleteness as checkEmrCompleteness} from '@/api/emr';
|
||||||
|
import {useRouter} from 'vue-router';
|
||||||
import {computed, getCurrentInstance, ref, watch} from 'vue';
|
import {computed, getCurrentInstance, ref, watch} from 'vue';
|
||||||
import {formatDate as formatDateUtil} from '@/utils/index';
|
import {formatDate as formatDateUtil} from '@/utils/index';
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
// Props
|
// Props
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
patientInfo: {
|
patientInfo: {
|
||||||
@@ -320,6 +339,37 @@ function handleSaveTemplate() {
|
|||||||
openEmrTemplate.value = true;
|
openEmrTemplate.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查看修订历史
|
||||||
|
function viewRevisionHistory() {
|
||||||
|
if (!props.patientInfo?.encounterId) {
|
||||||
|
proxy.$message.warning('请先选择患者');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
router.push({
|
||||||
|
path: '/emr/revision-history',
|
||||||
|
query: { emrId: props.patientInfo.encounterId }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 完整性检查
|
||||||
|
async function checkCompleteness() {
|
||||||
|
if (!props.patientInfo?.encounterId) {
|
||||||
|
proxy.$message.warning('请先选择患者');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const res = await checkEmrCompleteness(props.patientInfo.encounterId, props.patientInfo.encounterId);
|
||||||
|
const data = res.data || res;
|
||||||
|
if (data.isComplete) {
|
||||||
|
proxy.$modal.msgSuccess('病历完整性检查通过');
|
||||||
|
} else {
|
||||||
|
proxy.$message.warning(`病历完整性检查未通过,${data.requiredFailed}项必填项未填写`);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
proxy.$message.error('检查失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 选择模板/历史
|
// 选择模板/历史
|
||||||
function templateSelect(row) {
|
function templateSelect(row) {
|
||||||
form.value = { ...row };
|
form.value = { ...row };
|
||||||
|
|||||||
@@ -226,13 +226,19 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import {ref,onMounted} from 'vue'
|
import {ref,onMounted} from 'vue'
|
||||||
|
import {useRoute} from 'vue-router'
|
||||||
import {ElMessage,ElMessageBox} from 'element-plus'
|
import {ElMessage,ElMessageBox} from 'element-plus'
|
||||||
import {getArchivePage,archive,reprint,getArchiveStats} from './api'
|
import {getArchivePage,archive,reprint,getArchiveStats} from './api'
|
||||||
|
const route=useRoute()
|
||||||
const tableData=ref([]);const total=ref(0);const stats=ref({})
|
const tableData=ref([]);const total=ref(0);const stats=ref({})
|
||||||
const q=ref({pageNo:1,pageSize:20,patientName:'',archiveStatus:''})
|
const q=ref({pageNo:1,pageSize:20,patientName:'',archiveStatus:''})
|
||||||
const loadData=async()=>{const r=await getArchivePage(q.value);tableData.value=r.data?.records||[];total.value=r.data?.total||0}
|
const loadData=async()=>{const r=await getArchivePage(q.value);tableData.value=r.data?.records||[];total.value=r.data?.total||0}
|
||||||
const loadStats=async()=>{const r=await getArchiveStats();stats.value=r.data||{}}
|
const loadStats=async()=>{const r=await getArchiveStats();stats.value=r.data||{}}
|
||||||
const doArchive=async(row)=>{const {value}=await ElMessageBox.prompt('归档人','确认归档');if(value){await archive(row.id,value);ElMessage.success('已归档');loadData();loadStats()}}
|
const doArchive=async(row)=>{const {value}=await ElMessageBox.prompt('归档人','确认归档');if(value){await archive(row.id,value);ElMessage.success('已归档');loadData();loadStats()}}
|
||||||
const doReprint=async(row)=>{await reprint(row.id);ElMessage.success('补打记录已添加');loadData()}
|
const doReprint=async(row)=>{await reprint(row.id);ElMessage.success('补打记录已添加');loadData()}
|
||||||
onMounted(()=>{loadData();loadStats()})
|
onMounted(()=>{
|
||||||
|
if(route.query.encounterId){q.value.encounterId=route.query.encounterId}
|
||||||
|
if(route.query.patientName){q.value.patientName=route.query.patientName}
|
||||||
|
loadData();loadStats()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -90,10 +90,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, computed } from 'vue'
|
import { ref, reactive, computed, onMounted } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
import { checkCompleteness, getCompletenessResults } from '@/api/emr'
|
import { checkCompleteness, getCompletenessResults } from '@/api/emr'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
const checkLoading = ref(false)
|
const checkLoading = ref(false)
|
||||||
const resultLoading = ref(false)
|
const resultLoading = ref(false)
|
||||||
const checkResult = ref(null)
|
const checkResult = ref(null)
|
||||||
@@ -148,6 +150,12 @@ const loadResults = async () => {
|
|||||||
resultLoading.value = false
|
resultLoading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (route.query.emrId) { checkForm.emrId = route.query.emrId }
|
||||||
|
if (route.query.encounterId) { checkForm.encounterId = route.query.encounterId }
|
||||||
|
if (checkForm.emrId && checkForm.encounterId) { handleCheck() }
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
export function getRevisionPage(p){return request({url:'/emr-revision/page',method:'get',params:p})}
|
export function getRevisionPage(p){return request({url:'/emr/revision/page',method:'get',params:p})}
|
||||||
export function getRevisionList(p){return request({url:'/emr-revision/list',method:'get',params:p})}
|
export function getRevisionList(emrId){return request({url:'/emr/revision/list/'+emrId,method:'get'})}
|
||||||
export function recordRevision(d){return request({url:'/emr-revision/record',method:'post',data:d})}
|
export function recordRevision(d){return request({url:'/emr/revision/record',method:'post',data:d})}
|
||||||
export function compareRevisions(id1,id2){return request({url:'/emr-revision/compare',method:'get',params:{revisionId1:id1,revisionId2:id2}})}
|
export function compareRevisions(id1,id2){return request({url:'/emr/revision/compare',method:'get',params:{revisionId1:id1,revisionId2:id2}})}
|
||||||
|
|||||||
@@ -129,11 +129,16 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import {ref,onMounted} from 'vue'
|
import {ref,onMounted} from 'vue'
|
||||||
|
import {useRoute} from 'vue-router'
|
||||||
import {getRevisionPage} from './api'
|
import {getRevisionPage} from './api'
|
||||||
|
const route=useRoute()
|
||||||
const tableData=ref([]);const total=ref(0)
|
const tableData=ref([]);const total=ref(0)
|
||||||
const q=ref({pageNo:1,pageSize:20,emrId:'',operatorName:''})
|
const q=ref({pageNo:1,pageSize:20,emrId:'',operatorName:''})
|
||||||
const detailVisible=ref(false);const detail=ref({})
|
const detailVisible=ref(false);const detail=ref({})
|
||||||
const loadData=async()=>{const r=await getRevisionPage(q.value);tableData.value=r.data?.records||[];total.value=r.data?.total||0}
|
const loadData=async()=>{const r=await getRevisionPage(q.value);tableData.value=r.data?.records||[];total.value=r.data?.total||0}
|
||||||
const viewDetail=(row)=>{detail.value=row;detailVisible.value=true}
|
const viewDetail=(row)=>{detail.value=row;detailVisible.value=true}
|
||||||
onMounted(()=>loadData())
|
onMounted(()=>{
|
||||||
|
if(route.query.emrId){q.value.emrId=route.query.emrId}
|
||||||
|
loadData()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -132,14 +132,20 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onMounted } from 'vue'
|
import { ref, reactive, onMounted } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
import { getTimelinessByEncounter, getOverdueList, getTimelinessStatistics } from '@/api/emr'
|
import { getTimelinessByEncounter, getOverdueList, getTimelinessStatistics } from '@/api/emr'
|
||||||
|
const route = useRoute()
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const dataList = ref([])
|
const dataList = ref([])
|
||||||
const stats = reactive({ pending: 0, completed: 0, overdue: 0, rate: 0 })
|
const stats = reactive({ pending: 0, completed: 0, overdue: 0, rate: 0 })
|
||||||
const queryParams = reactive({ departmentName: '', emrType: '' })
|
const queryParams = reactive({ departmentName: '', emrType: '', encounterId: '' })
|
||||||
const emrTypeMap = { ADMISSION: '入院记录', FIRST_COURSE: '首次病程', DAILY_COURSE: '日常病程', DISCHARGE: '出院记录' }
|
const emrTypeMap = { ADMISSION: '入院记录', FIRST_COURSE: '首次病程', DAILY_COURSE: '日常病程', DISCHARGE: '出院记录' }
|
||||||
const statusMap = { PENDING: { label: '待完成', type: 'info' }, COMPLETED: { label: '已完成', type: 'success' }, OVERDUE: { label: '超时', type: 'danger' } }
|
const statusMap = { PENDING: { label: '待完成', type: 'info' }, COMPLETED: { label: '已完成', type: 'success' }, OVERDUE: { label: '超时', type: 'danger' } }
|
||||||
const getList = async () => { loading.value = true; const res = await getOverdueList(); dataList.value = res.data || res.rows || []; loading.value = false }
|
const getList = async () => { loading.value = true; const res = await getOverdueList(); dataList.value = res.data || res.rows || []; loading.value = false }
|
||||||
const handleQuery = () => getList()
|
const handleQuery = () => getList()
|
||||||
onMounted(() => { getList() })
|
onMounted(() => {
|
||||||
|
if (route.query.encounterId) { queryParams.encounterId = route.query.encounterId }
|
||||||
|
if (route.query.departmentName) { queryParams.departmentName = route.query.departmentName }
|
||||||
|
getList()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -120,8 +120,10 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {ref,reactive,onMounted} from 'vue'
|
import {ref,reactive,onMounted} from 'vue'
|
||||||
|
import {useRoute} from 'vue-router'
|
||||||
import {searchEmr} from './api'
|
import {searchEmr} from './api'
|
||||||
|
|
||||||
|
const route=useRoute()
|
||||||
const loading=ref(false)
|
const loading=ref(false)
|
||||||
const searchData=ref([])
|
const searchData=ref([])
|
||||||
const total=ref(0)
|
const total=ref(0)
|
||||||
@@ -132,5 +134,10 @@ const handleSearch=async()=>{
|
|||||||
try{const r=await searchEmr(queryParams);searchData.value=r.data?.records||[];total.value=r.data?.total||0}finally{loading.value=false}
|
try{const r=await searchEmr(queryParams);searchData.value=r.data?.records||[];total.value=r.data?.total||0}finally{loading.value=false}
|
||||||
}
|
}
|
||||||
const resetQuery=()=>{Object.assign(queryParams,{keyword:'',patientName:'',emrType:'',doctorName:'',pageNo:1});handleSearch()}
|
const resetQuery=()=>{Object.assign(queryParams,{keyword:'',patientName:'',emrType:'',doctorName:'',pageNo:1});handleSearch()}
|
||||||
onMounted(()=>handleSearch())
|
onMounted(()=>{
|
||||||
|
if(route.query.patientName){queryParams.patientName=route.query.patientName}
|
||||||
|
if(route.query.emrType){queryParams.emrType=route.query.emrType}
|
||||||
|
if(route.query.keyword){queryParams.keyword=route.query.keyword}
|
||||||
|
handleSearch()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -78,6 +78,20 @@
|
|||||||
>
|
>
|
||||||
打印表单
|
打印表单
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="info"
|
||||||
|
plain
|
||||||
|
@click="viewRevisionHistory"
|
||||||
|
>
|
||||||
|
修订历史
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="info"
|
||||||
|
plain
|
||||||
|
@click="checkCompleteness"
|
||||||
|
>
|
||||||
|
完整性检查
|
||||||
|
</el-button>
|
||||||
<!-- <el-button type="primary" @click="" disabled>病案上传</el-button>
|
<!-- <el-button type="primary" @click="" disabled>病案上传</el-button>
|
||||||
<el-button type="primary" @click="">结算上传</el-button> -->
|
<el-button type="primary" @click="">结算上传</el-button> -->
|
||||||
<!-- <el-button type="primary" @click="onNursingStatus">护理状态</el-button> -->
|
<!-- <el-button type="primary" @click="onNursingStatus">护理状态</el-button> -->
|
||||||
@@ -923,6 +937,41 @@ const onPrint = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 查看修订历史
|
||||||
|
import {useRouter} from 'vue-router';
|
||||||
|
import {checkCompleteness as checkEmrCompleteness} from '@/api/emr';
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const viewRevisionHistory = () => {
|
||||||
|
if (!patientInfo.value?.encounterId) {
|
||||||
|
ElMessage.warning('请先选择患者');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
router.push({
|
||||||
|
path: '/emr/revision-history',
|
||||||
|
query: { emrId: patientInfo.value.encounterId }
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 完整性检查
|
||||||
|
const checkCompleteness = async () => {
|
||||||
|
if (!patientInfo.value?.encounterId) {
|
||||||
|
ElMessage.warning('请先选择患者');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const res = await checkEmrCompleteness(patientInfo.value.encounterId, patientInfo.value.encounterId);
|
||||||
|
const data = res.data || res;
|
||||||
|
if (data.isComplete) {
|
||||||
|
ElMessage.success('病历完整性检查通过');
|
||||||
|
} else {
|
||||||
|
ElMessage.warning(`病历完整性检查未通过,${data.requiredFailed}项必填项未填写`);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error('检查失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 添加一个方法供父组件调用,处理患者切换
|
// 添加一个方法供父组件调用,处理患者切换
|
||||||
const handlePatientChange = (patient) => {
|
const handlePatientChange = (patient) => {
|
||||||
// 更新患者信息
|
// 更新患者信息
|
||||||
|
|||||||
Reference in New Issue
Block a user