feat: 洗美报告图片表重构 - ReportImage实体,支持多图上传

This commit is contained in:
MaDaLei 2026-04-16 21:20:28 +08:00
parent 3604b4bb78
commit 3298574159
6 changed files with 162 additions and 38 deletions

View File

@ -1,6 +1,7 @@
package com.petstore.controller; package com.petstore.controller;
import com.petstore.entity.Report; import com.petstore.entity.Report;
import com.petstore.entity.ReportImage;
import com.petstore.entity.Store; import com.petstore.entity.Store;
import com.petstore.service.ReportService; import com.petstore.service.ReportService;
import com.petstore.service.StoreService; import com.petstore.service.StoreService;
@ -9,9 +10,7 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import java.util.HashMap; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@RestController @RestController
@ -75,10 +74,23 @@ public class ReportController {
item.put("staffName", r.getStaffName()); item.put("staffName", r.getStaffName());
item.put("reportToken", r.getReportToken()); item.put("reportToken", r.getReportToken());
item.put("createTime", r.getCreateTime()); item.put("createTime", r.getCreateTime());
item.put("beforePhoto", fullUrl(r.getBeforePhoto()));
item.put("afterPhoto", fullUrl(r.getAfterPhoto()));
item.put("storeId", r.getStoreId()); item.put("storeId", r.getStoreId());
item.put("userId", r.getUserId()); item.put("userId", r.getUserId());
// 图片列表
List<ReportImage> imgs = r.getImages();
List<String> beforePhotos = new ArrayList<>();
List<String> afterPhotos = new ArrayList<>();
if (imgs != null) {
for (ReportImage img : imgs) {
if ("before".equals(img.getPhotoType())) {
beforePhotos.add(fullUrl(img.getPhotoUrl()));
} else if ("after".equals(img.getPhotoType())) {
afterPhotos.add(fullUrl(img.getPhotoUrl()));
}
}
}
item.put("beforePhotos", beforePhotos);
item.put("afterPhotos", afterPhotos);
return item; return item;
}).collect(Collectors.toList()); }).collect(Collectors.toList());
if (usePaging && paged != null) { if (usePaging && paged != null) {
@ -115,8 +127,21 @@ public class ReportController {
Map<String, Object> data = new HashMap<>(); Map<String, Object> data = new HashMap<>();
data.put("id", report.getId()); data.put("id", report.getId());
data.put("appointmentId", report.getAppointmentId()); data.put("appointmentId", report.getAppointmentId());
data.put("beforePhoto", report.getBeforePhoto()); // 图片列表
data.put("afterPhoto", report.getAfterPhoto()); List<ReportImage> imgs = report.getImages();
List<String> beforePhotos = new ArrayList<>();
List<String> afterPhotos = new ArrayList<>();
if (imgs != null) {
for (ReportImage img : imgs) {
if ("before".equals(img.getPhotoType())) {
beforePhotos.add(img.getPhotoUrl());
} else if ("after".equals(img.getPhotoType())) {
afterPhotos.add(img.getPhotoUrl());
}
}
}
data.put("beforePhotos", beforePhotos);
data.put("afterPhotos", afterPhotos);
data.put("remark", report.getRemark()); data.put("remark", report.getRemark());
data.put("userId", report.getUserId()); data.put("userId", report.getUserId());
data.put("storeId", report.getStoreId()); data.put("storeId", report.getStoreId());

View File

@ -2,8 +2,11 @@ package com.petstore.entity;
import jakarta.persistence.*; import jakarta.persistence.*;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data; import lombok.Data;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Data @Data
@Entity @Entity
@ -24,14 +27,12 @@ public class Report {
@Column(name = "appointment_id") @Column(name = "appointment_id")
private Long appointmentId; private Long appointmentId;
@Column(name = "before_photo", columnDefinition = "TEXT")
private String beforePhoto;
@Column(name = "after_photo", columnDefinition = "TEXT")
private String afterPhoto;
private String remark; private String remark;
@Transient
@JsonIgnore
private List<ReportImage> images = new ArrayList<>();
@Column(name = "user_id") @Column(name = "user_id")
private Long userId; private Long userId;

View File

@ -0,0 +1,47 @@
package com.petstore.entity;
import jakarta.persistence.*;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@Entity
@Table(name = "t_report_image")
public class ReportImage {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "report_id", insertable = false, updatable = false)
@JsonIgnore
private Report report;
@Column(name = "report_id")
private Long reportId;
@Column(name = "photo_url", length = 500)
private String photoUrl;
/** 图片类型before=服务前after=服务后 */
@Column(name = "photo_type", length = 20)
private String photoType;
/** 排序序号,同类型内按顺序展示 */
@Column(name = "sort_order")
private Integer sortOrder;
@Column(name = "create_time")
private LocalDateTime createTime;
@PrePersist
protected void onCreate() {
if (createTime == null) {
createTime = LocalDateTime.now();
}
if (sortOrder == null) {
sortOrder = 0;
}
}
}

View File

@ -0,0 +1,16 @@
package com.petstore.mapper;
import com.petstore.entity.ReportImage;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ReportImageMapper extends JpaRepository<ReportImage, Long> {
List<ReportImage> findByReportIdOrderBySortOrderAsc(Long reportId);
List<ReportImage> findByReportIdAndPhotoTypeOrderBySortOrderAsc(Long reportId, String photoType);
void deleteByReportId(Long reportId);
List<ReportImage> findByReportIdIn(List<Long> reportIds);
}

View File

@ -26,4 +26,5 @@ public interface ReportMapper extends JpaRepository<Report, Long> {
Page<Report> findByUserId(Long userId, Pageable pageable); Page<Report> findByUserId(Long userId, Pageable pageable);
Page<Report> findByStoreIdAndUserId(Long storeId, Long userId, Pageable pageable); Page<Report> findByStoreIdAndUserId(Long storeId, Long userId, Pageable pageable);
} }

View File

@ -1,11 +1,7 @@
package com.petstore.service; package com.petstore.service;
import com.petstore.entity.Appointment; import com.petstore.entity.*;
import com.petstore.entity.Report; import com.petstore.mapper.*;
import com.petstore.entity.User;
import com.petstore.mapper.AppointmentMapper;
import com.petstore.mapper.ReportMapper;
import com.petstore.mapper.UserMapper;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
@ -21,6 +17,7 @@ import java.util.UUID;
@RequiredArgsConstructor @RequiredArgsConstructor
public class ReportService { public class ReportService {
private final ReportMapper reportMapper; private final ReportMapper reportMapper;
private final ReportImageMapper reportImageMapper;
private final AppointmentMapper appointmentMapper; private final AppointmentMapper appointmentMapper;
private final UserMapper userMapper; private final UserMapper userMapper;
@ -63,34 +60,68 @@ public class ReportService {
report.setCreateTime(LocalDateTime.now()); report.setCreateTime(LocalDateTime.now());
report.setUpdateTime(LocalDateTime.now()); report.setUpdateTime(LocalDateTime.now());
return reportMapper.save(report);
// 先保存 Report 以获取生成的 ID
Report saved = reportMapper.save(report);
// 处理图片列表设置 reportId 后通过 reportImageMapper 保存
if (saved.getImages() != null && !saved.getImages().isEmpty()) {
for (ReportImage img : saved.getImages()) {
img.setReportId(saved.getId());
reportImageMapper.save(img);
}
}
return saved;
}
/** 查询单条报告并填充图片 */
private Report enrichImages(Report r) {
if (r == null) return null;
List<ReportImage> imgs = reportImageMapper.findByReportIdOrderBySortOrderAsc(r.getId());
r.setImages(imgs);
return r;
}
/** 批量填充图片(列表用) */
private List<Report> enrichImages(List<Report> reports) {
if (reports == null || reports.isEmpty()) return reports;
List<Long> ids = reports.stream().map(Report::getId).toList();
List<ReportImage> allImages = reportImageMapper.findByReportIdIn(ids);
java.util.Map<Long, List<ReportImage>> map = allImages.stream()
.collect(java.util.stream.Collectors.groupingBy(ReportImage::getReportId));
for (Report r : reports) {
r.setImages(map.getOrDefault(r.getId(), java.util.List.of()));
}
return reports;
} }
public Report getByAppointmentId(Long appointmentId) { public Report getByAppointmentId(Long appointmentId) {
if (appointmentId == null) { if (appointmentId == null) {
return null; return null;
} }
return reportMapper.findFirstByAppointmentIdOrderByCreateTimeDesc(appointmentId).orElse(null); return enrichImages(reportMapper.findFirstByAppointmentIdOrderByCreateTimeDesc(appointmentId).orElse(null));
} }
public Report getByToken(String token) { public Report getByToken(String token) {
if (token == null || token.isBlank()) { if (token == null || token.isBlank()) {
return null; return null;
} }
return reportMapper.findFirstByReportToken(token).orElse(null); return enrichImages(reportMapper.findFirstByReportToken(token).orElse(null));
} }
public List<Report> list(Long storeId, Long userId) { public List<Report> list(Long storeId, Long userId) {
List<Report> reports;
if (storeId != null && userId != null) { if (storeId != null && userId != null) {
return reportMapper.findByStoreIdAndUserIdOrderByCreateTimeDesc(storeId, userId); reports = reportMapper.findByStoreIdAndUserIdOrderByCreateTimeDesc(storeId, userId);
} else if (storeId != null) {
reports = reportMapper.findByStoreIdOrderByCreateTimeDesc(storeId);
} else if (userId != null) {
reports = reportMapper.findByUserIdOrderByCreateTimeDesc(userId);
} else {
reports = reportMapper.findAllByOrderByCreateTimeDesc();
} }
if (storeId != null) { return enrichImages(reports);
return reportMapper.findByStoreIdOrderByCreateTimeDesc(storeId);
}
if (userId != null) {
return reportMapper.findByUserIdOrderByCreateTimeDesc(userId);
}
return reportMapper.findAllByOrderByCreateTimeDesc();
} }
public Page<Report> page(Long storeId, Long userId, int pageNo, int pageSize) { public Page<Report> page(Long storeId, Long userId, int pageNo, int pageSize) {
@ -99,15 +130,18 @@ public class ReportService {
Math.max(pageSize, 1), Math.max(pageSize, 1),
Sort.by(Sort.Direction.DESC, "createTime") Sort.by(Sort.Direction.DESC, "createTime")
); );
Page<Report> paged;
if (storeId != null && userId != null) { if (storeId != null && userId != null) {
return reportMapper.findByStoreIdAndUserId(storeId, userId, pageable); paged = reportMapper.findByStoreIdAndUserId(storeId, userId, pageable);
} else if (storeId != null) {
paged = reportMapper.findByStoreId(storeId, pageable);
} else if (userId != null) {
paged = reportMapper.findByUserId(userId, pageable);
} else {
paged = reportMapper.findAll(pageable);
} }
if (storeId != null) { // 填充图片
return reportMapper.findByStoreId(storeId, pageable); enrichImages(paged.getContent());
} return paged;
if (userId != null) {
return reportMapper.findByUserId(userId, pageable);
}
return reportMapper.findAll(pageable);
} }
} }