feat(nursing): T6.2 营养风险筛查NRS2002功能

This commit is contained in:
2026-06-18 12:14:48 +08:00
parent 7c3c22d029
commit 90ee407d5a
4 changed files with 232 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
package com.healthlink.his.web.nursing.appservice;
import com.healthlink.his.nursing.domain.NursingAssessment;
import java.util.List;
public interface INutritionScreeningAppService {
NursingAssessment screenNutrition(NursingAssessment assessment);
List<NursingAssessment> getScreeningRecords(Long encounterId);
}

View File

@@ -0,0 +1,43 @@
package com.healthlink.his.web.nursing.appservice.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.healthlink.his.nursing.domain.NursingAssessment;
import com.healthlink.his.nursing.service.INursingAssessmentService;
import com.healthlink.his.web.nursing.appservice.INutritionScreeningAppService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class NutritionScreeningAppServiceImpl implements INutritionScreeningAppService {
@Autowired
private INursingAssessmentService assessmentService;
@Override
public NursingAssessment screenNutrition(NursingAssessment assessment) {
assessment.setAssessmentTool("NRS2002");
assessment.setAssessmentType("NUTRITION");
assessment.setRiskLevel(calculateNutritionRiskLevel(assessment));
assessment.setDeleteFlag("0");
assessmentService.save(assessment);
return assessment;
}
@Override
public List<NursingAssessment> getScreeningRecords(Long encounterId) {
return assessmentService.list(new LambdaQueryWrapper<NursingAssessment>()
.eq(NursingAssessment::getEncounterId, encounterId)
.eq(NursingAssessment::getAssessmentTool, "NRS2002")
.orderByDesc(NursingAssessment::getAssessmentTime));
}
private String calculateNutritionRiskLevel(NursingAssessment assessment) {
Integer totalScore = assessment.getTotalScore();
if (totalScore == null) return "NORMAL";
if (totalScore >= 3) return "HIGH";
if (totalScore == 2) return "MEDIUM";
return "LOW";
}
}

View File

@@ -0,0 +1,36 @@
package com.healthlink.his.web.nursing.controller;
import com.core.common.core.domain.AjaxResult;
import com.healthlink.his.nursing.domain.NursingAssessment;
import com.healthlink.his.web.nursing.appservice.INutritionScreeningAppService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Tag(name = "营养风险筛查NRS2002")
@RestController
@RequestMapping("/api/v1/nursing/nutrition")
public class NutritionScreeningController {
@Autowired
private INutritionScreeningAppService nutritionScreeningAppService;
@Operation(summary = "营养风险筛查")
@PostMapping("/screen")
@PreAuthorize("hasAuthority('nursing:nursing:edit')")
public AjaxResult screenNutrition(@RequestBody NursingAssessment assessment) {
return AjaxResult.success(nutritionScreeningAppService.screenNutrition(assessment));
}
@Operation(summary = "获取营养风险筛查记录")
@GetMapping("/list/{encounterId}")
@PreAuthorize("hasAuthority('nursing:nursing:list')")
public AjaxResult getScreeningRecords(@PathVariable Long encounterId) {
List<NursingAssessment> records = nutritionScreeningAppService.getScreeningRecords(encounterId);
return AjaxResult.success(records);
}
}

View File

@@ -0,0 +1,143 @@
<template>
<div class="app-container">
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>营养风险筛查NRS2002</span>
</div>
</template>
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="就诊号" prop="encounterId">
<el-input v-model="form.encounterId" placeholder="请输入就诊号" />
</el-form-item>
<el-form-item label="患者ID" prop="patientId">
<el-input v-model="form.patientId" placeholder="请输入患者ID" />
</el-form-item>
<el-form-item label="患者姓名" prop="patientName">
<el-input v-model="form.patientName" placeholder="请输入患者姓名" />
</el-form-item>
<el-form-item label="总评分" prop="totalScore">
<el-input-number v-model="form.totalScore" :min="0" :max="10" />
</el-form-item>
<el-form-item label="评估详情" prop="detail">
<el-input v-model="form.detail" type="textarea" :rows="4" placeholder="请输入评估详情" />
</el-form-item>
<el-form-item label="评估人" prop="assessorName">
<el-input v-model="form.assessorName" placeholder="请输入评估人姓名" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitScreen">提交筛查</el-button>
<el-button @click="resetForm">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card class="box-card" style="margin-top: 20px;">
<template #header>
<div class="card-header">
<span>筛查记录</span>
</div>
</template>
<el-table v-loading="loading" :data="records" style="width: 100%">
<el-table-column label="总评分" prop="totalScore" width="80" />
<el-table-column label="风险等级" prop="riskLevel" width="100">
<template #default="scope">
<el-tag :type="getRiskType(scope.row.riskLevel)">
{{ scope.row.riskLevel }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="评估详情" prop="detail" />
<el-table-column label="评估人" prop="assessorName" width="100" />
<el-table-column label="评估时间" prop="assessmentTime" width="170" />
</el-table>
</el-card>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import request from '@/utils/request'
const formRef = ref(null)
const loading = ref(false)
const records = ref([])
const form = reactive({
encounterId: '',
patientId: '',
patientName: '',
totalScore: 0,
detail: '',
assessorName: ''
})
const rules = {
encounterId: [{ required: true, message: '请输入就诊号', trigger: 'blur' }],
patientId: [{ required: true, message: '请输入患者ID', trigger: 'blur' }],
patientName: [{ required: true, message: '请输入患者姓名', trigger: 'blur' }],
totalScore: [{ required: true, message: '请输入总评分', trigger: 'blur' }],
assessorName: [{ required: true, message: '请输入评估人', trigger: 'blur' }]
}
const getRiskType = (level) => {
const map = { HIGH: 'danger', MEDIUM: 'warning', LOW: 'success', NORMAL: 'info' }
return map[level] || 'info'
}
const submitScreen = async () => {
try {
await formRef.value.validate()
loading.value = true
await request({
url: '/api/v1/nursing/nutrition/screen',
method: 'post',
data: form
})
ElMessage.success('筛查提交成功')
getRecords()
resetForm()
} catch (error) {
ElMessage.error('提交失败')
} finally {
loading.value = false
}
}
const getRecords = async () => {
if (!form.encounterId) return
loading.value = true
try {
const res = await request({
url: `/api/v1/nursing/nutrition/list/${form.encounterId}`,
method: 'get'
})
records.value = res.data || []
} catch (error) {
ElMessage.error('获取记录失败')
} finally {
loading.value = false
}
}
const resetForm = () => {
formRef.value?.resetFields()
}
onMounted(() => {
if (form.encounterId) {
getRecords()
}
})
</script>
<style scoped>
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>