diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/review/appservice/IReviewAppService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/review/appservice/IReviewAppService.java index 8f953c9e2..da463db80 100644 --- a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/review/appservice/IReviewAppService.java +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/review/appservice/IReviewAppService.java @@ -8,4 +8,11 @@ public interface IReviewAppService { List getRecordsByPlan(Long planId); Map getStatistics(String startDate, String endDate); List> getDoctorRanking(String startDate, String endDate); + + com.baomidou.mybatisplus.core.metadata.IPage listPlans(String planName, String status, Integer pageNum, Integer pageSize); + ReviewPlan getPlanById(Long id); + void updatePlan(ReviewPlan p); + void deletePlan(Long id); + com.baomidou.mybatisplus.core.metadata.IPage listRecords(String prescriptionNo, String reviewResult, Integer pageNum, Integer pageSize); + List> autoScreen(Map params); } diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/review/appservice/impl/ReviewAppServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/review/appservice/impl/ReviewAppServiceImpl.java index 2a0fa6f2e..27980283e 100644 --- a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/review/appservice/impl/ReviewAppServiceImpl.java +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/review/appservice/impl/ReviewAppServiceImpl.java @@ -12,23 +12,23 @@ public class ReviewAppServiceImpl implements IReviewAppService { @Autowired private IReviewRecordService recordService; @Override - public ReviewPlan createPlan(ReviewPlan p) { p.setStatus("ACTIVE"); p.setDelFlag("0"); planService.save(p); return p; } + public ReviewPlan createPlan(ReviewPlan p) { p.setStatus("ACTIVE"); planService.save(p); return p; } @Override public void submitReview(ReviewRecord r) { - r.setDelFlag("0"); r.setReviewTime(new Date()); recordService.save(r); + r.setReviewTime(new Date()); recordService.save(r); ReviewPlan plan = planService.getById(r.getPlanId()); if (plan != null) { plan.setReviewedCount(plan.getReviewedCount() == null ? 1 : plan.getReviewedCount() + 1); planService.updateById(plan); } } @Override public List getRecordsByPlan(Long planId) { - return recordService.list(new LambdaQueryWrapper().eq(ReviewRecord::getPlanId, planId).eq(ReviewRecord::getDelFlag, "0")); + return recordService.list(new LambdaQueryWrapper().eq(ReviewRecord::getPlanId, planId)); } @Override public Map getStatistics(String startDate, String endDate) { Map r = new HashMap<>(); - r.put("totalPlans", planService.count(new LambdaQueryWrapper().eq(ReviewPlan::getDelFlag, "0"))); - r.put("totalRecords", recordService.count(new LambdaQueryWrapper().eq(ReviewRecord::getDelFlag, "0"))); - long unreasonable = recordService.count(new LambdaQueryWrapper().eq(ReviewRecord::getReviewResult, "UNREASONABLE").eq(ReviewRecord::getDelFlag, "0")); + r.put("totalPlans", planService.count(new LambdaQueryWrapper())); + r.put("totalRecords", recordService.count(new LambdaQueryWrapper())); + long unreasonable = recordService.count(new LambdaQueryWrapper().eq(ReviewRecord::getReviewResult, "UNREASONABLE")); r.put("unreasonableCount", unreasonable); long total = r.get("totalRecords") != null ? (long) r.get("totalRecords") : 0; r.put("reasonableRate", total > 0 ? Math.round((total - unreasonable) * 100.0 / total) : 100); @@ -36,4 +36,40 @@ public class ReviewAppServiceImpl implements IReviewAppService { } @Override public List> getDoctorRanking(String startDate, String endDate) { return Collections.emptyList(); } + + @Override + public com.baomidou.mybatisplus.core.metadata.IPage listPlans(String planName, String status, Integer pageNum, Integer pageSize) { + LambdaQueryWrapper w = new LambdaQueryWrapper<>(); + if (planName != null && !planName.isEmpty()) w.like(ReviewPlan::getPlanName, planName); + if (status != null && !status.isEmpty()) w.eq(ReviewPlan::getStatus, status); + w.orderByDesc(ReviewPlan::getCreateTime); + return planService.page(new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageNum, pageSize), w); + } + + @Override + public ReviewPlan getPlanById(Long id) { return planService.getById(id); } + + @Override + public void updatePlan(ReviewPlan p) { planService.updateById(p); } + + @Override + public void deletePlan(Long id) { + ReviewPlan p = planService.getById(id); + if (p != null) { planService.removeById(id); } + } + + @Override + public com.baomidou.mybatisplus.core.metadata.IPage listRecords(String prescriptionNo, String reviewResult, Integer pageNum, Integer pageSize) { + LambdaQueryWrapper w = new LambdaQueryWrapper<>(); + if (prescriptionNo != null && !prescriptionNo.isEmpty()) w.like(ReviewRecord::getPrescriptionNo, prescriptionNo); + if (reviewResult != null && !reviewResult.isEmpty()) w.eq(ReviewRecord::getReviewResult, reviewResult); + w.orderByDesc(ReviewRecord::getReviewTime); + return recordService.page(new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageNum, pageSize), w); + } + + @Override + public List> autoScreen(Map params) { + // TODO: 自动筛查逻辑 - 基于规则库筛查不合理处方 + return Collections.emptyList(); + } } diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/review/controller/ReviewController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/review/controller/ReviewController.java index e2a14ccce..0cfd8f884 100644 --- a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/review/controller/ReviewController.java +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/review/controller/ReviewController.java @@ -17,4 +17,55 @@ public class ReviewController { public AjaxResult records(@PathVariable Long planId) { return AjaxResult.success(reviewAppService.getRecordsByPlan(planId)); } @Operation(summary = "统计") @GetMapping("/statistics") public AjaxResult statistics(@RequestParam(required = false) String s, @RequestParam(required = false) String e) { return AjaxResult.success(reviewAppService.getStatistics(s, e)); } + + @Operation(summary = "查询计划列表") + @GetMapping("/plans") + public AjaxResult listPlans(@RequestParam(required = false) String planName, + @RequestParam(required = false) String status, + @RequestParam(defaultValue = "1") Integer pageNum, + @RequestParam(defaultValue = "10") Integer pageSize) { + return AjaxResult.success(reviewAppService.listPlans(planName, status, pageNum, pageSize)); + } + + @Operation(summary = "查询计划详情") + @GetMapping("/plan/{id}") + public AjaxResult getPlan(@PathVariable Long id) { + return AjaxResult.success(reviewAppService.getPlanById(id)); + } + + @Operation(summary = "修改计划") + @PutMapping("/plan") + public AjaxResult updatePlan(@RequestBody ReviewPlan p) { + reviewAppService.updatePlan(p); + return AjaxResult.success(); + } + + @Operation(summary = "删除计划") + @DeleteMapping("/plan/{id}") + public AjaxResult deletePlan(@PathVariable Long id) { + reviewAppService.deletePlan(id); + return AjaxResult.success(); + } + + @Operation(summary = "查询点评记录列表") + @GetMapping("/records") + public AjaxResult listRecords(@RequestParam(required = false) String prescriptionNo, + @RequestParam(required = false) String reviewResult, + @RequestParam(defaultValue = "1") Integer pageNum, + @RequestParam(defaultValue = "10") Integer pageSize) { + return AjaxResult.success(reviewAppService.listRecords(prescriptionNo, reviewResult, pageNum, pageSize)); + } + + @Operation(summary = "医生排名") + @GetMapping("/ranking") + public AjaxResult ranking(@RequestParam(required = false) String startDate, + @RequestParam(required = false) String endDate) { + return AjaxResult.success(reviewAppService.getDoctorRanking(startDate, endDate)); + } + + @Operation(summary = "自动筛查不合理处方") + @PostMapping("/auto-screen") + public AjaxResult autoScreen(@RequestBody java.util.Map params) { + return AjaxResult.success(reviewAppService.autoScreen(params)); + } } diff --git a/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V37__review_tables.sql b/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V37__review_tables.sql new file mode 100644 index 000000000..2f080d06e --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V37__review_tables.sql @@ -0,0 +1,52 @@ +-- 处方点评计划表 +CREATE TABLE IF NOT EXISTS healthlink_his.review_plan ( + id BIGSERIAL PRIMARY KEY, + plan_name VARCHAR(200) NOT NULL, + review_type VARCHAR(50), + department_ids TEXT, + doctor_ids TEXT, + dept_name VARCHAR(100), + target_count INTEGER DEFAULT 50, + sample_count INTEGER, + reviewed_count INTEGER DEFAULT 0, + start_date DATE, + end_date DATE, + status VARCHAR(20) DEFAULT 'ACTIVE', + remark TEXT, + del_flag CHAR(1) DEFAULT '0', + create_by VARCHAR(64), + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by VARCHAR(64), + update_time TIMESTAMP +); + +-- 处方点评记录表 +CREATE TABLE IF NOT EXISTS healthlink_his.review_record ( + id BIGSERIAL PRIMARY KEY, + plan_id BIGINT, + prescription_id BIGINT, + prescription_no VARCHAR(50), + encounter_id BIGINT, + patient_id BIGINT, + patient_name VARCHAR(100), + doctor_id BIGINT, + doctor_name VARCHAR(100), + department_name VARCHAR(100), + review_result VARCHAR(20), + problem_type VARCHAR(50), + problem_detail TEXT, + unreasonable_type VARCHAR(200), + comment TEXT, + reviewer_id BIGINT, + reviewer_name VARCHAR(100), + review_time TIMESTAMP, + del_flag CHAR(1) DEFAULT '0', + create_by VARCHAR(64), + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by VARCHAR(64), + update_time TIMESTAMP +); + +CREATE INDEX IF NOT EXISTS idx_review_plan_status ON healthlink_his.review_plan(status); +CREATE INDEX IF NOT EXISTS idx_review_record_plan ON healthlink_his.review_record(plan_id); +CREATE INDEX IF NOT EXISTS idx_review_record_result ON healthlink_his.review_record(review_result); diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/review/domain/ReviewPlan.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/review/domain/ReviewPlan.java index 73697ca03..fdf5fb00f 100644 --- a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/review/domain/ReviewPlan.java +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/review/domain/ReviewPlan.java @@ -12,5 +12,5 @@ public class ReviewPlan extends HisBaseEntity { private String departmentIds; private String doctorIds; private Date startDate; private Date endDate; private Integer sampleCount; private Integer reviewedCount; - private String status; private String delFlag; + private String deptName; private Integer targetCount; private String remark; private String status; } diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/review/domain/ReviewRecord.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/review/domain/ReviewRecord.java index 9f47397fb..b4f320002 100644 --- a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/review/domain/ReviewRecord.java +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/review/domain/ReviewRecord.java @@ -11,7 +11,7 @@ public class ReviewRecord extends HisBaseEntity { private Long planId; private Long prescriptionId; private Long encounterId; private Long patientId; private String patientName; private Long doctorId; private String doctorName; private String departmentName; - private String reviewResult; private String problemType; private String problemDetail; + private String reviewResult; private String problemType; private String problemDetail; private String unreasonableType; private String comment; private String prescriptionNo; private Long reviewerId; private String reviewerName; private Date reviewTime; - private String delFlag; + } diff --git a/healthlink-his-ui/src/api/review.js b/healthlink-his-ui/src/api/review.js new file mode 100644 index 000000000..66a98a923 --- /dev/null +++ b/healthlink-his-ui/src/api/review.js @@ -0,0 +1,46 @@ +import request from '@/utils/request' + +// ==================== 处方点评 ==================== +export function createPlan(data) { + return request({ url: '/api/v1/review/plan', method: 'post', data }) +} + +export function listPlans(params) { + return request({ url: '/api/v1/review/plans', method: 'get', params }) +} + +export function getPlanDetail(id) { + return request({ url: `/api/v1/review/plan/${id}`, method: 'get' }) +} + +export function updatePlan(data) { + return request({ url: '/api/v1/review/plan', method: 'put', data }) +} + +export function deletePlan(id) { + return request({ url: `/api/v1/review/plan/${id}`, method: 'delete' }) +} + +export function submitReview(data) { + return request({ url: '/api/v1/review/record', method: 'post', data }) +} + +export function getRecordsByPlan(planId) { + return request({ url: `/api/v1/review/records/${planId}`, method: 'get' }) +} + +export function listRecords(params) { + return request({ url: '/api/v1/review/records', method: 'get', params }) +} + +export function getStatistics(params) { + return request({ url: '/api/v1/review/statistics', method: 'get', params }) +} + +export function getDoctorRanking(params) { + return request({ url: '/api/v1/review/ranking', method: 'get', params }) +} + +export function autoScreen(data) { + return request({ url: '/api/v1/review/auto-screen', method: 'post', data }) +} diff --git a/healthlink-his-ui/src/views/review/plan/index.vue b/healthlink-his-ui/src/views/review/plan/index.vue new file mode 100644 index 000000000..b80ccf5ab --- /dev/null +++ b/healthlink-his-ui/src/views/review/plan/index.vue @@ -0,0 +1,86 @@ + + diff --git a/healthlink-his-ui/src/views/review/ranking/index.vue b/healthlink-his-ui/src/views/review/ranking/index.vue new file mode 100644 index 000000000..0f02243d9 --- /dev/null +++ b/healthlink-his-ui/src/views/review/ranking/index.vue @@ -0,0 +1,39 @@ + + diff --git a/healthlink-his-ui/src/views/review/records/index.vue b/healthlink-his-ui/src/views/review/records/index.vue new file mode 100644 index 000000000..d2c361afc --- /dev/null +++ b/healthlink-his-ui/src/views/review/records/index.vue @@ -0,0 +1,38 @@ + + diff --git a/healthlink-his-ui/src/views/review/workbench/index.vue b/healthlink-his-ui/src/views/review/workbench/index.vue new file mode 100644 index 000000000..41044ae9a --- /dev/null +++ b/healthlink-his-ui/src/views/review/workbench/index.vue @@ -0,0 +1,73 @@ + +