test
This commit is contained in:
@@ -47,7 +47,7 @@ public class AppointmentController {
|
||||
return ApiResponse.success(appointmentService.page(new Page<>(page, size), wrapper));
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
@GetMapping("/admin")
|
||||
public ApiResponse<?> adminList(@RequestParam(defaultValue = "1") long page,
|
||||
@RequestParam(defaultValue = "10") long size,
|
||||
@@ -59,7 +59,7 @@ public class AppointmentController {
|
||||
return ApiResponse.success(appointmentService.page(new Page<>(page, size), wrapper));
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
@PutMapping("/{id}/status")
|
||||
public ApiResponse<?> updateStatus(@PathVariable Long id, @RequestParam String status) {
|
||||
Appointment update = new Appointment();
|
||||
|
||||
@@ -17,7 +17,7 @@ public class DrugController {
|
||||
this.drugService = drugService;
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
@GetMapping
|
||||
public ApiResponse<?> list(@RequestParam(defaultValue = "1") long page,
|
||||
@RequestParam(defaultValue = "10") long size,
|
||||
@@ -31,7 +31,7 @@ public class DrugController {
|
||||
return ApiResponse.success(drugService.page(new Page<>(page, size), wrapper));
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@PostMapping
|
||||
public ApiResponse<?> create(@RequestBody Drug drug) {
|
||||
if (drug.getStatus() == null) {
|
||||
@@ -41,7 +41,7 @@ public class DrugController {
|
||||
return ApiResponse.success("created", null);
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@PutMapping("/{id}")
|
||||
public ApiResponse<?> update(@PathVariable Long id, @RequestBody Drug drug) {
|
||||
drug.setId(id);
|
||||
@@ -49,7 +49,7 @@ public class DrugController {
|
||||
return ApiResponse.success("updated", null);
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@DeleteMapping("/{id}")
|
||||
public ApiResponse<?> delete(@PathVariable Long id) {
|
||||
drugService.removeById(id);
|
||||
|
||||
@@ -16,7 +16,7 @@ public class MedicalRecordController {
|
||||
this.medicalRecordService = medicalRecordService;
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
@PostMapping
|
||||
public ApiResponse<?> create(@RequestBody MedicalRecord record) {
|
||||
if (record.getStatus() == null) {
|
||||
@@ -33,7 +33,7 @@ public class MedicalRecordController {
|
||||
return ApiResponse.success(medicalRecordService.list(wrapper));
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
@PutMapping("/{id}")
|
||||
public ApiResponse<?> update(@PathVariable Long id, @RequestBody MedicalRecord record) {
|
||||
record.setId(id);
|
||||
@@ -41,7 +41,7 @@ public class MedicalRecordController {
|
||||
return ApiResponse.success("updated", null);
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@DeleteMapping("/{id}")
|
||||
public ApiResponse<?> delete(@PathVariable Long id) {
|
||||
medicalRecordService.removeById(id);
|
||||
|
||||
@@ -35,7 +35,7 @@ public class MessageController {
|
||||
return ApiResponse.success("created", null);
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@GetMapping("/admin")
|
||||
public ApiResponse<?> list(@RequestParam(defaultValue = "1") long page,
|
||||
@RequestParam(defaultValue = "10") long size,
|
||||
@@ -47,7 +47,7 @@ public class MessageController {
|
||||
return ApiResponse.success(messageService.page(new Page<>(page, size), wrapper));
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@PutMapping("/admin/{id}/reply")
|
||||
public ApiResponse<?> reply(@PathVariable Long id, @Valid @RequestBody ReplyRequest request) {
|
||||
AuthUser user = SecurityUtils.currentUser();
|
||||
|
||||
@@ -34,14 +34,14 @@ public class NoticeController {
|
||||
return ApiResponse.success(noticeService.getById(id));
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@GetMapping("/notices")
|
||||
public ApiResponse<?> list(@RequestParam(defaultValue = "1") long page,
|
||||
@RequestParam(defaultValue = "10") long size) {
|
||||
return ApiResponse.success(noticeService.page(new Page<>(page, size)));
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@PostMapping("/notices")
|
||||
public ApiResponse<?> create(@RequestBody Notice notice) {
|
||||
if (notice.getPublisherId() == null) {
|
||||
@@ -60,7 +60,7 @@ public class NoticeController {
|
||||
return ApiResponse.success("created", null);
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@PutMapping("/notices/{id}")
|
||||
public ApiResponse<?> update(@PathVariable Long id, @RequestBody Notice notice) {
|
||||
notice.setId(id);
|
||||
@@ -68,7 +68,7 @@ public class NoticeController {
|
||||
return ApiResponse.success("updated", null);
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@DeleteMapping("/notices/{id}")
|
||||
public ApiResponse<?> delete(@PathVariable Long id) {
|
||||
noticeService.removeById(id);
|
||||
|
||||
@@ -44,7 +44,7 @@ public class OrderController {
|
||||
/**
|
||||
* 根据处方生成订单
|
||||
*/
|
||||
@// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
@PostMapping("/from-prescription/{prescriptionId}")
|
||||
public ApiResponse<?> createFromPrescription(@PathVariable Long prescriptionId) {
|
||||
// 1. 查询处方
|
||||
@@ -164,7 +164,7 @@ public class OrderController {
|
||||
return ApiResponse.success(orderService.page(new Page<>(page, size), wrapper));
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
@PutMapping("/{id}")
|
||||
public ApiResponse<?> update(@PathVariable Long id, @RequestBody Order order) {
|
||||
order.setId(id);
|
||||
|
||||
@@ -72,7 +72,7 @@ public class PetController {
|
||||
return ApiResponse.success("deleted", null);
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@GetMapping("/admin/all")
|
||||
public ApiResponse<?> adminList(@RequestParam(defaultValue = "1") long page,
|
||||
@RequestParam(defaultValue = "10") long size) {
|
||||
|
||||
@@ -19,7 +19,7 @@ public class PrescriptionController {
|
||||
this.prescriptionService = prescriptionService;
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
@PostMapping
|
||||
public ApiResponse<?> create(@RequestBody Prescription prescription) {
|
||||
if (prescription.getStatus() == null) {
|
||||
@@ -44,7 +44,7 @@ public class PrescriptionController {
|
||||
return ApiResponse.success(prescriptionService.page(new Page<>(page, size), wrapper));
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
@PutMapping("/{id}")
|
||||
public ApiResponse<?> update(@PathVariable Long id, @RequestBody Prescription prescription) {
|
||||
prescription.setId(id);
|
||||
|
||||
@@ -23,14 +23,14 @@ public class PrescriptionItemController {
|
||||
return ApiResponse.success(prescriptionItemService.list(wrapper));
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
@PostMapping
|
||||
public ApiResponse<?> create(@RequestBody PrescriptionItem item) {
|
||||
prescriptionItemService.save(item);
|
||||
return ApiResponse.success("created", null);
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
@PutMapping("/{id}")
|
||||
public ApiResponse<?> update(@PathVariable Long id, @RequestBody PrescriptionItem item) {
|
||||
item.setId(id);
|
||||
@@ -38,7 +38,7 @@ public class PrescriptionItemController {
|
||||
return ApiResponse.success("updated", null);
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
@DeleteMapping("/{id}")
|
||||
public ApiResponse<?> delete(@PathVariable Long id) {
|
||||
prescriptionItemService.removeById(id);
|
||||
|
||||
@@ -19,7 +19,7 @@ public class ReportController {
|
||||
this.reportService = reportService;
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
@PostMapping
|
||||
public ApiResponse<?> create(@RequestBody Report report) {
|
||||
AuthUser user = SecurityUtils.currentUser();
|
||||
@@ -45,7 +45,7 @@ public class ReportController {
|
||||
return ApiResponse.success(reportService.page(new Page<>(page, size), wrapper));
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
@PutMapping("/{id}")
|
||||
public ApiResponse<?> update(@PathVariable Long id, @RequestBody Report report) {
|
||||
report.setId(id);
|
||||
@@ -53,7 +53,7 @@ public class ReportController {
|
||||
return ApiResponse.success("updated", null);
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@DeleteMapping("/{id}")
|
||||
public ApiResponse<?> delete(@PathVariable Long id) {
|
||||
reportService.removeById(id);
|
||||
|
||||
@@ -6,12 +6,14 @@ import com.gpf.pethospital.common.ApiResponse;
|
||||
import com.gpf.pethospital.entity.Appointment;
|
||||
import com.gpf.pethospital.entity.Order;
|
||||
import com.gpf.pethospital.entity.Pet;
|
||||
import com.gpf.pethospital.entity.PrescriptionItem;
|
||||
import com.gpf.pethospital.entity.User;
|
||||
import com.gpf.pethospital.entity.Visit;
|
||||
import com.gpf.pethospital.service.AppointmentService;
|
||||
import com.gpf.pethospital.service.DrugService;
|
||||
import com.gpf.pethospital.service.OrderService;
|
||||
import com.gpf.pethospital.service.PetService;
|
||||
import com.gpf.pethospital.service.PrescriptionItemService;
|
||||
import com.gpf.pethospital.service.UserService;
|
||||
import com.gpf.pethospital.service.VisitService;
|
||||
// import org.springframework.security.access.prepost.PreAuthorize;
|
||||
@@ -26,8 +28,11 @@ import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -40,22 +45,25 @@ public class StatsController {
|
||||
private final PetService petService;
|
||||
private final UserService userService;
|
||||
private final DrugService drugService;
|
||||
private final PrescriptionItemService prescriptionItemService;
|
||||
|
||||
public StatsController(OrderService orderService,
|
||||
AppointmentService appointmentService,
|
||||
VisitService visitService,
|
||||
PetService petService,
|
||||
UserService userService,
|
||||
DrugService drugService) {
|
||||
DrugService drugService,
|
||||
PrescriptionItemService prescriptionItemService) {
|
||||
this.orderService = orderService;
|
||||
this.appointmentService = appointmentService;
|
||||
this.visitService = visitService;
|
||||
this.petService = petService;
|
||||
this.userService = userService;
|
||||
this.drugService = drugService;
|
||||
this.prescriptionItemService = prescriptionItemService;
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@GetMapping
|
||||
public ApiResponse<?> summary() {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
@@ -124,7 +132,7 @@ public class StatsController {
|
||||
return ApiResponse.success(data);
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@GetMapping("/trends")
|
||||
public ApiResponse<?> trends(@RequestParam(defaultValue = "week") String period) {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
@@ -208,8 +216,253 @@ public class StatsController {
|
||||
|
||||
return ApiResponse.success(data);
|
||||
}
|
||||
|
||||
@GetMapping("/report/revenue")
|
||||
public ApiResponse<?> revenueReport(@RequestParam(defaultValue = "month") String period,
|
||||
@RequestParam(required = false) String startDate,
|
||||
@RequestParam(required = false) String endDate) {
|
||||
DateRange range = resolveDateRange(period, startDate, endDate);
|
||||
List<Order> paidOrders = orderService.list(
|
||||
new LambdaQueryWrapper<Order>()
|
||||
.eq(Order::getStatus, "PAID")
|
||||
.ge(Order::getCreateTime, range.start())
|
||||
.lt(Order::getCreateTime, range.end())
|
||||
);
|
||||
|
||||
Map<LocalDate, BigDecimal> amountByDay = new HashMap<>();
|
||||
BigDecimal totalAmount = BigDecimal.ZERO;
|
||||
for (Order order : paidOrders) {
|
||||
BigDecimal amount = order.getAmount() == null ? BigDecimal.ZERO : order.getAmount();
|
||||
totalAmount = totalAmount.add(amount);
|
||||
if (order.getCreateTime() != null) {
|
||||
amountByDay.merge(order.getCreateTime().toLocalDate(), amount, BigDecimal::add);
|
||||
}
|
||||
}
|
||||
|
||||
List<Map<String, Object>> trend = amountByDay.entrySet().stream()
|
||||
.sorted(Map.Entry.comparingByKey())
|
||||
.map(entry -> {
|
||||
Map<String, Object> point = new HashMap<>();
|
||||
point.put("date", entry.getKey().toString());
|
||||
point.put("amount", entry.getValue());
|
||||
return point;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
DateRange previous = range.shiftBack();
|
||||
BigDecimal previousTotalAmount = sumPaidOrderAmount(previous.start(), previous.end());
|
||||
double growthRate = BigDecimal.ZERO.compareTo(previousTotalAmount) == 0
|
||||
? 0D
|
||||
: totalAmount.subtract(previousTotalAmount)
|
||||
.multiply(BigDecimal.valueOf(100))
|
||||
.divide(previousTotalAmount, 2, java.math.RoundingMode.HALF_UP)
|
||||
.doubleValue();
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("period", period);
|
||||
data.put("startDate", range.start().toLocalDate().toString());
|
||||
data.put("endDate", range.end().minusDays(1).toLocalDate().toString());
|
||||
data.put("totalAmount", totalAmount);
|
||||
data.put("orderCount", paidOrders.size());
|
||||
data.put("averageAmount", paidOrders.isEmpty()
|
||||
? BigDecimal.ZERO
|
||||
: totalAmount.divide(BigDecimal.valueOf(paidOrders.size()), 2, java.math.RoundingMode.HALF_UP));
|
||||
data.put("growthRate", growthRate);
|
||||
data.put("trend", trend);
|
||||
return ApiResponse.success(data);
|
||||
}
|
||||
|
||||
@GetMapping("/report/revenue-sources")
|
||||
public ApiResponse<?> revenueSources(@RequestParam(defaultValue = "month") String period,
|
||||
@RequestParam(required = false) String startDate,
|
||||
@RequestParam(required = false) String endDate) {
|
||||
DateRange range = resolveDateRange(period, startDate, endDate);
|
||||
QueryWrapper<Order> wrapper = new QueryWrapper<>();
|
||||
wrapper.select("payment_method AS paymentMethod", "COUNT(*) AS orderCount", "COALESCE(SUM(amount), 0) AS totalAmount");
|
||||
wrapper.eq("status", "PAID");
|
||||
wrapper.ge("create_time", range.start());
|
||||
wrapper.lt("create_time", range.end());
|
||||
wrapper.groupBy("payment_method");
|
||||
wrapper.orderByDesc("totalAmount");
|
||||
|
||||
List<Map<String, Object>> rows = orderService.listMaps(wrapper);
|
||||
BigDecimal totalAmount = rows.stream()
|
||||
.map(row -> toBigDecimal(getMapValue(row, "totalAmount", "totalamount", "TOTALAMOUNT")))
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
|
||||
List<Map<String, Object>> sources = new ArrayList<>();
|
||||
for (Map<String, Object> row : rows) {
|
||||
BigDecimal amount = toBigDecimal(getMapValue(row, "totalAmount", "totalamount", "TOTALAMOUNT"));
|
||||
Map<String, Object> item = new HashMap<>();
|
||||
item.put("paymentMethod", normalizePaymentMethod(String.valueOf(getMapValue(row, "paymentMethod", "payment_method", "PAYMENTMETHOD"))));
|
||||
item.put("orderCount", toLong(getMapValue(row, "orderCount", "ordercount", "ORDERCOUNT")));
|
||||
item.put("totalAmount", amount);
|
||||
item.put("ratio", BigDecimal.ZERO.compareTo(totalAmount) == 0
|
||||
? BigDecimal.ZERO
|
||||
: amount.multiply(BigDecimal.valueOf(100)).divide(totalAmount, 2, java.math.RoundingMode.HALF_UP));
|
||||
sources.add(item);
|
||||
}
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("period", period);
|
||||
data.put("startDate", range.start().toLocalDate().toString());
|
||||
data.put("endDate", range.end().minusDays(1).toLocalDate().toString());
|
||||
data.put("totalAmount", totalAmount);
|
||||
data.put("sources", sources);
|
||||
return ApiResponse.success(data);
|
||||
}
|
||||
|
||||
@GetMapping("/report/drug-sales")
|
||||
public ApiResponse<?> drugSales(@RequestParam(defaultValue = "month") String period,
|
||||
@RequestParam(required = false) String startDate,
|
||||
@RequestParam(required = false) String endDate,
|
||||
@RequestParam(defaultValue = "10") int limit) {
|
||||
DateRange range = resolveDateRange(period, startDate, endDate);
|
||||
QueryWrapper<PrescriptionItem> wrapper = new QueryWrapper<>();
|
||||
wrapper.select("drug_id AS drugId", "drug_name AS drugName", "COALESCE(SUM(quantity), 0) AS totalQuantity", "COALESCE(SUM(subtotal), 0) AS totalAmount");
|
||||
wrapper.ge("create_time", range.start());
|
||||
wrapper.lt("create_time", range.end());
|
||||
wrapper.groupBy("drug_id", "drug_name");
|
||||
wrapper.orderByDesc("totalQuantity");
|
||||
wrapper.orderByDesc("totalAmount");
|
||||
wrapper.last("LIMIT " + safeLimit(limit, 100));
|
||||
|
||||
List<Map<String, Object>> rows = prescriptionItemService.listMaps(wrapper);
|
||||
List<Map<String, Object>> ranking = new ArrayList<>();
|
||||
int rank = 1;
|
||||
for (Map<String, Object> row : rows) {
|
||||
Map<String, Object> item = new HashMap<>();
|
||||
item.put("rank", rank++);
|
||||
item.put("drugId", toLong(getMapValue(row, "drugId", "drug_id", "DRUGID")));
|
||||
item.put("drugName", normalizeDrugName(getMapValue(row, "drugName", "drug_name", "DRUGNAME")));
|
||||
item.put("totalQuantity", toLong(getMapValue(row, "totalQuantity", "totalquantity", "TOTALQUANTITY")));
|
||||
item.put("totalAmount", toBigDecimal(getMapValue(row, "totalAmount", "totalamount", "TOTALAMOUNT")));
|
||||
ranking.add(item);
|
||||
}
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("period", period);
|
||||
data.put("startDate", range.start().toLocalDate().toString());
|
||||
data.put("endDate", range.end().minusDays(1).toLocalDate().toString());
|
||||
data.put("ranking", ranking);
|
||||
return ApiResponse.success(data);
|
||||
}
|
||||
|
||||
@GetMapping("/report/doctor-performance")
|
||||
public ApiResponse<?> doctorPerformance(@RequestParam(defaultValue = "month") String period,
|
||||
@RequestParam(required = false) String startDate,
|
||||
@RequestParam(required = false) String endDate,
|
||||
@RequestParam(defaultValue = "10") int limit) {
|
||||
DateRange range = resolveDateRange(period, startDate, endDate);
|
||||
QueryWrapper<Visit> wrapper = new QueryWrapper<>();
|
||||
wrapper.select("doctor_id AS doctorId", "COUNT(*) AS visitCount", "COALESCE(SUM(total_amount), 0) AS totalAmount", "COALESCE(AVG(total_amount), 0) AS averageAmount");
|
||||
wrapper.ge("create_time", range.start());
|
||||
wrapper.lt("create_time", range.end());
|
||||
wrapper.isNotNull("doctor_id");
|
||||
wrapper.groupBy("doctor_id");
|
||||
wrapper.orderByDesc("totalAmount");
|
||||
wrapper.last("LIMIT " + safeLimit(limit, 100));
|
||||
|
||||
List<Map<String, Object>> rows = visitService.listMaps(wrapper);
|
||||
Set<Long> doctorIds = rows.stream()
|
||||
.map(row -> toLong(getMapValue(row, "doctorId", "doctor_id", "DOCTORID")))
|
||||
.filter(id -> id > 0)
|
||||
.collect(Collectors.toSet());
|
||||
Map<Long, String> doctorNameMap = userService.listByIds(doctorIds).stream()
|
||||
.collect(Collectors.toMap(User::getId, User::getUsername, (left, right) -> left));
|
||||
|
||||
List<Map<String, Object>> ranking = new ArrayList<>();
|
||||
int rank = 1;
|
||||
for (Map<String, Object> row : rows) {
|
||||
Long doctorId = toLong(getMapValue(row, "doctorId", "doctor_id", "DOCTORID"));
|
||||
Map<String, Object> item = new HashMap<>();
|
||||
item.put("rank", rank++);
|
||||
item.put("doctorId", doctorId);
|
||||
item.put("doctorName", doctorNameMap.getOrDefault(doctorId, "医生#" + doctorId));
|
||||
item.put("visitCount", toLong(getMapValue(row, "visitCount", "visitcount", "VISITCOUNT")));
|
||||
item.put("totalAmount", toBigDecimal(getMapValue(row, "totalAmount", "totalamount", "TOTALAMOUNT")));
|
||||
item.put("averageAmount", toBigDecimal(getMapValue(row, "averageAmount", "averageamount", "AVERAGEAMOUNT")));
|
||||
ranking.add(item);
|
||||
}
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("period", period);
|
||||
data.put("startDate", range.start().toLocalDate().toString());
|
||||
data.put("endDate", range.end().minusDays(1).toLocalDate().toString());
|
||||
data.put("ranking", ranking);
|
||||
return ApiResponse.success(data);
|
||||
}
|
||||
|
||||
@GetMapping("/report/department-performance")
|
||||
public ApiResponse<?> departmentPerformance(@RequestParam(defaultValue = "month") String period,
|
||||
@RequestParam(required = false) String startDate,
|
||||
@RequestParam(required = false) String endDate) {
|
||||
DateRange range = resolveDateRange(period, startDate, endDate);
|
||||
|
||||
QueryWrapper<Appointment> appointmentWrapper = new QueryWrapper<>();
|
||||
appointmentWrapper.select("department", "COUNT(*) AS appointmentCount");
|
||||
appointmentWrapper.ge("create_time", range.start());
|
||||
appointmentWrapper.lt("create_time", range.end());
|
||||
appointmentWrapper.groupBy("department");
|
||||
List<Map<String, Object>> appointmentRows = appointmentService.listMaps(appointmentWrapper);
|
||||
|
||||
Map<String, Long> appointmentCountMap = new HashMap<>();
|
||||
for (Map<String, Object> row : appointmentRows) {
|
||||
String department = normalizeDepartment(getMapValue(row, "department", "DEPARTMENT"));
|
||||
appointmentCountMap.put(department, toLong(getMapValue(row, "appointmentCount", "appointmentcount", "APPOINTMENTCOUNT")));
|
||||
}
|
||||
|
||||
List<Visit> visits = visitService.list(
|
||||
new LambdaQueryWrapper<Visit>()
|
||||
.ge(Visit::getCreateTime, range.start())
|
||||
.lt(Visit::getCreateTime, range.end())
|
||||
.isNotNull(Visit::getAppointmentId)
|
||||
);
|
||||
|
||||
Set<Long> appointmentIds = visits.stream()
|
||||
.map(Visit::getAppointmentId)
|
||||
.filter(id -> id != null && id > 0)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Map<Long, Appointment> appointmentMap = appointmentIds.isEmpty()
|
||||
? new HashMap<>()
|
||||
: appointmentService.listByIds(appointmentIds).stream()
|
||||
.collect(Collectors.toMap(Appointment::getId, appointment -> appointment, (left, right) -> left));
|
||||
|
||||
Map<String, Long> visitCountMap = new HashMap<>();
|
||||
Map<String, BigDecimal> revenueMap = new HashMap<>();
|
||||
for (Visit visit : visits) {
|
||||
Appointment appointment = appointmentMap.get(visit.getAppointmentId());
|
||||
String department = normalizeDepartment(appointment == null ? null : appointment.getDepartment());
|
||||
visitCountMap.merge(department, 1L, Long::sum);
|
||||
revenueMap.merge(department, visit.getTotalAmount() == null ? BigDecimal.ZERO : visit.getTotalAmount(), BigDecimal::add);
|
||||
}
|
||||
|
||||
Set<String> departments = new HashSet<>();
|
||||
departments.addAll(appointmentCountMap.keySet());
|
||||
departments.addAll(visitCountMap.keySet());
|
||||
|
||||
List<Map<String, Object>> departmentsData = departments.stream()
|
||||
.map(department -> {
|
||||
Map<String, Object> row = new HashMap<>();
|
||||
row.put("department", department);
|
||||
row.put("appointmentCount", appointmentCountMap.getOrDefault(department, 0L));
|
||||
row.put("visitCount", visitCountMap.getOrDefault(department, 0L));
|
||||
row.put("totalAmount", revenueMap.getOrDefault(department, BigDecimal.ZERO));
|
||||
return row;
|
||||
})
|
||||
.sorted((left, right) -> toBigDecimal(right.get("totalAmount")).compareTo(toBigDecimal(left.get("totalAmount"))))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("period", period);
|
||||
data.put("startDate", range.start().toLocalDate().toString());
|
||||
data.put("endDate", range.end().minusDays(1).toLocalDate().toString());
|
||||
data.put("departments", departmentsData);
|
||||
return ApiResponse.success(data);
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@GetMapping("/today-todos")
|
||||
public ApiResponse<?> todayTodos() {
|
||||
LocalDate today = LocalDate.now();
|
||||
@@ -243,4 +496,139 @@ public class StatsController {
|
||||
|
||||
return ApiResponse.success(todoList);
|
||||
}
|
||||
|
||||
private DateRange resolveDateRange(String period, String startDate, String endDate) {
|
||||
if (hasText(startDate) && hasText(endDate)) {
|
||||
LocalDate start = LocalDate.parse(startDate);
|
||||
LocalDate end = LocalDate.parse(endDate);
|
||||
if (end.isBefore(start)) {
|
||||
LocalDate temp = start;
|
||||
start = end;
|
||||
end = temp;
|
||||
}
|
||||
return new DateRange(start.atStartOfDay(), end.plusDays(1).atStartOfDay());
|
||||
}
|
||||
|
||||
LocalDate today = LocalDate.now();
|
||||
LocalDate start;
|
||||
LocalDate end = today.plusDays(1);
|
||||
switch (period) {
|
||||
case "day":
|
||||
start = today;
|
||||
break;
|
||||
case "week":
|
||||
start = today.minusDays(6);
|
||||
break;
|
||||
case "year":
|
||||
start = today.minusMonths(11).withDayOfMonth(1);
|
||||
end = today.plusMonths(1).withDayOfMonth(1);
|
||||
break;
|
||||
case "month":
|
||||
default:
|
||||
start = today.minusDays(29);
|
||||
break;
|
||||
}
|
||||
return new DateRange(start.atStartOfDay(), end.atStartOfDay());
|
||||
}
|
||||
|
||||
private BigDecimal sumPaidOrderAmount(LocalDateTime start, LocalDateTime end) {
|
||||
QueryWrapper<Order> wrapper = new QueryWrapper<>();
|
||||
wrapper.select("COALESCE(SUM(amount), 0) AS totalAmount");
|
||||
wrapper.eq("status", "PAID");
|
||||
wrapper.ge("create_time", start);
|
||||
wrapper.lt("create_time", end);
|
||||
List<Map<String, Object>> rows = orderService.listMaps(wrapper);
|
||||
if (rows.isEmpty()) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return toBigDecimal(getMapValue(rows.get(0), "totalAmount", "totalamount", "TOTALAMOUNT"));
|
||||
}
|
||||
|
||||
private boolean hasText(String value) {
|
||||
return value != null && !value.isBlank();
|
||||
}
|
||||
|
||||
private int safeLimit(int value, int maxLimit) {
|
||||
if (value <= 0) {
|
||||
return 10;
|
||||
}
|
||||
return Math.min(value, maxLimit);
|
||||
}
|
||||
|
||||
private BigDecimal toBigDecimal(Object value) {
|
||||
if (value == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
if (value instanceof BigDecimal) {
|
||||
return (BigDecimal) value;
|
||||
}
|
||||
try {
|
||||
return new BigDecimal(value.toString());
|
||||
} catch (NumberFormatException ex) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
private long toLong(Object value) {
|
||||
if (value == null) {
|
||||
return 0L;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).longValue();
|
||||
}
|
||||
try {
|
||||
return Long.parseLong(value.toString());
|
||||
} catch (NumberFormatException ex) {
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
private Object getMapValue(Map<String, Object> row, String... keys) {
|
||||
for (String key : keys) {
|
||||
if (row.containsKey(key)) {
|
||||
return row.get(key);
|
||||
}
|
||||
}
|
||||
for (String key : keys) {
|
||||
for (Map.Entry<String, Object> entry : row.entrySet()) {
|
||||
if (entry.getKey().equalsIgnoreCase(key)) {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String normalizeDepartment(Object value) {
|
||||
String department = value == null ? "" : value.toString().trim();
|
||||
return department.isEmpty() ? "未分配科室" : department;
|
||||
}
|
||||
|
||||
private String normalizePaymentMethod(String value) {
|
||||
if (value == null || value.isBlank()) {
|
||||
return "未知支付方式";
|
||||
}
|
||||
switch (value) {
|
||||
case "ALIPAY":
|
||||
return "支付宝";
|
||||
case "WECHAT":
|
||||
return "微信支付";
|
||||
case "OFFLINE":
|
||||
return "线下支付";
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private String normalizeDrugName(Object value) {
|
||||
String name = value == null ? "" : value.toString().trim();
|
||||
return name.isEmpty() ? "未知药品" : name;
|
||||
}
|
||||
|
||||
private record DateRange(LocalDateTime start, LocalDateTime end) {
|
||||
private DateRange shiftBack() {
|
||||
long days = Math.max(1, ChronoUnit.DAYS.between(start.toLocalDate(), end.toLocalDate()));
|
||||
return new DateRange(start.minusDays(days), start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ public class StockInController {
|
||||
this.drugService = drugService;
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@GetMapping
|
||||
public ApiResponse<?> list(@RequestParam(defaultValue = "1") long page,
|
||||
@RequestParam(defaultValue = "10") long size,
|
||||
@@ -34,7 +34,7 @@ public class StockInController {
|
||||
return ApiResponse.success(stockInService.page(new Page<>(page, size), wrapper));
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@PostMapping
|
||||
@Transactional
|
||||
public ApiResponse<?> create(@RequestBody StockIn stockIn) {
|
||||
|
||||
@@ -22,7 +22,7 @@ public class StockOutController {
|
||||
this.drugService = drugService;
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@GetMapping
|
||||
public ApiResponse<?> list(@RequestParam(defaultValue = "1") long page,
|
||||
@RequestParam(defaultValue = "10") long size,
|
||||
@@ -34,7 +34,7 @@ public class StockOutController {
|
||||
return ApiResponse.success(stockOutService.page(new Page<>(page, size), wrapper));
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@PostMapping
|
||||
@Transactional
|
||||
public ApiResponse<?> create(@RequestBody StockOut stockOut) {
|
||||
|
||||
@@ -67,7 +67,7 @@ public class UserController {
|
||||
return ApiResponse.success(result);
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@PostMapping
|
||||
public ApiResponse<?> create(@RequestBody User user) {
|
||||
if (user.getPassword() == null || user.getPassword().isBlank()) {
|
||||
@@ -81,7 +81,7 @@ public class UserController {
|
||||
return ApiResponse.success("created", null);
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@PutMapping("/{id}/status")
|
||||
public ApiResponse<?> updateStatus(@PathVariable Long id, @RequestParam Integer status) {
|
||||
User update = new User();
|
||||
@@ -91,7 +91,7 @@ public class UserController {
|
||||
return ApiResponse.success("updated", null);
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@PutMapping("/{id}/reset-password")
|
||||
public ApiResponse<?> resetPassword(@PathVariable Long id, @RequestParam String newPassword) {
|
||||
User update = new User();
|
||||
@@ -101,7 +101,7 @@ public class UserController {
|
||||
return ApiResponse.success("updated", null);
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasRole('ADMIN')")
|
||||
// @PreAuthorize("hasRole('ADMIN')")
|
||||
@GetMapping("/stats")
|
||||
public ApiResponse<?> stats() {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
|
||||
@@ -19,7 +19,7 @@ public class VisitController {
|
||||
this.visitService = visitService;
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
@PostMapping
|
||||
public ApiResponse<?> create(@RequestBody Visit visit) {
|
||||
if (visit.getStatus() == null) {
|
||||
@@ -47,7 +47,7 @@ public class VisitController {
|
||||
return ApiResponse.success(visitService.page(new Page<>(page, size), wrapper));
|
||||
}
|
||||
|
||||
@// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
// @PreAuthorize("hasAnyRole('ADMIN','DOCTOR')")
|
||||
@PutMapping("/{id}")
|
||||
public ApiResponse<?> update(@PathVariable Long id, @RequestBody Visit visit) {
|
||||
visit.setId(id);
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
@@ -52,6 +53,16 @@ public class Report {
|
||||
*/
|
||||
private Long doctorId;
|
||||
|
||||
private String reportType;
|
||||
|
||||
private String reportData;
|
||||
|
||||
private LocalDate periodStart;
|
||||
|
||||
private LocalDate periodEnd;
|
||||
|
||||
private Long generatedBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user