docs: reorganize documentation structure

This commit is contained in:
张翔
2026-03-05 13:48:13 +08:00
parent 349b0a754f
commit 104fa7e7c8
59 changed files with 22859 additions and 916 deletions
@@ -0,0 +1,139 @@
package com.gym.manage.application.service;
import com.gym.manage.api.dto.request.BookingCreateRequest;
import com.gym.manage.api.dto.response.BookingRecordResponse;
import com.gym.manage.common.constant.ErrorCode;
import com.gym.manage.common.exception.BusinessException;
import com.gym.manage.domain.entity.BookingRecord;
import com.gym.manage.domain.entity.BookingSlot;
import com.gym.manage.domain.repository.BookingRecordRepository;
import com.gym.manage.domain.repository.BookingSlotRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
@Slf4j
@Service
@RequiredArgsConstructor
public class BookingService {
private final BookingSlotRepository bookingSlotRepository;
private final BookingRecordRepository bookingRecordRepository;
@Transactional
public Mono<BookingRecordResponse> createBooking(BookingCreateRequest request) {
log.info("创建预约: memberId={}, slotId={}", request.getMemberId(), request.getSlotId());
return validateAndBook(request)
.map(this::toBookingRecordResponse)
.doOnSuccess(response -> log.info("预约创建成功: bookingId={}", response.getId()))
.doOnError(e -> log.error("预约创建失败: memberId={}, slotId={}, error={}",
request.getMemberId(), request.getSlotId(), e.getMessage()));
}
private Mono<BookingRecord> validateAndBook(BookingCreateRequest request) {
return bookingSlotRepository.findByIdAndDeletedAtIsNull(request.getSlotId())
.switchIfEmpty(Mono.error(new BusinessException(ErrorCode.SLOT_NOT_FOUND, "时段不存在")))
.flatMap(slot -> {
if (!"AVAILABLE".equals(slot.getStatus())) {
return Mono.error(new BusinessException(ErrorCode.SLOT_NOT_AVAILABLE, "时段不可预约"));
}
if (slot.getBookedCount() >= slot.getMaxCapacity()) {
return Mono.error(new BusinessException(ErrorCode.SLOT_NOT_AVAILABLE, "时段已满"));
}
return bookingRecordRepository.findByMemberIdAndSlotIdAndDeletedAtIsNull(
request.getMemberId(), request.getSlotId()
).flatMap(existing -> Mono.<BookingRecord>error(
new BusinessException(ErrorCode.BOOKING_NOT_FOUND, "已预约该时段")
)).switchIfEmpty(createBookingRecord(request, slot));
});
}
private Mono<BookingRecord> createBookingRecord(BookingCreateRequest request, BookingSlot slot) {
return bookingSlotRepository.incrementBookedCount(request.getSlotId())
.flatMap(rows -> {
if (rows > 0) {
BookingRecord record = new BookingRecord();
record.setTenantId(slot.getTenantId());
record.setStoreId(slot.getStoreId());
record.setMemberId(request.getMemberId());
record.setSlotId(request.getSlotId());
record.setCoachId(slot.getCoachId());
record.setCourseName(slot.getCourseName());
record.setBookingTime(LocalDateTime.now());
record.setStatus("BOOKED");
record.setRemark(request.getRemark());
record.setCreatedAt(LocalDateTime.now());
record.setUpdatedAt(LocalDateTime.now());
return bookingRecordRepository.save(record);
} else {
return Mono.error(new BusinessException(ErrorCode.SLOT_NOT_AVAILABLE, "预约失败,请重试"));
}
});
}
public Mono<BookingRecordResponse> getBooking(Long id) {
log.info("查询预约: bookingId={}", id);
return bookingRecordRepository.findByIdAndDeletedAtIsNull(id)
.switchIfEmpty(Mono.error(new BusinessException(ErrorCode.BOOKING_NOT_FOUND, "预约不存在")))
.map(this::toBookingRecordResponse);
}
public Flux<BookingRecordResponse> listMemberBookings(Long memberId, int page, int size) {
log.info("查询会员预约列表: memberId={}", memberId);
return bookingRecordRepository.findByMemberIdAndDeletedAtIsNull(memberId,
org.springframework.data.domain.PageRequest.of(page, size))
.map(this::toBookingRecordResponse);
}
@Transactional
public Mono<Void> cancelBooking(Long id, String reason) {
log.info("取消预约: bookingId={}", id);
return bookingRecordRepository.findByIdAndDeletedAtIsNull(id)
.switchIfEmpty(Mono.error(new BusinessException(ErrorCode.BOOKING_NOT_FOUND, "预约不存在")))
.flatMap(record -> {
if ("CANCELLED".equals(record.getStatus())) {
return Mono.error(new BusinessException(ErrorCode.BOOKING_ALREADY_CANCELLED, "预约已取消"));
}
return bookingSlotRepository.decrementBookedCount(record.getSlotId())
.flatMap(rows -> {
record.setStatus("CANCELLED");
record.setCancelReason(reason);
record.setCancelTime(LocalDateTime.now());
record.setUpdatedAt(LocalDateTime.now());
return bookingRecordRepository.save(record);
});
})
.then();
}
private BookingRecordResponse toBookingRecordResponse(BookingRecord record) {
return BookingRecordResponse.builder()
.id(record.getId())
.memberId(record.getMemberId())
.slotId(record.getSlotId())
.coachId(record.getCoachId())
.courseName(record.getCourseName())
.bookingTime(record.getBookingTime())
.status(record.getStatus())
.cancelReason(record.getCancelReason())
.cancelTime(record.getCancelTime())
.checkinTime(record.getCheckinTime())
.remark(record.getRemark())
.createdAt(record.getCreatedAt())
.build();
}
}
@@ -0,0 +1,94 @@
package com.gym.manage.application.service;
import com.gym.manage.api.dto.request.MemberCardCreateRequest;
import com.gym.manage.api.dto.response.MemberCardResponse;
import com.gym.manage.common.constant.ErrorCode;
import com.gym.manage.common.exception.BusinessException;
import com.gym.manage.domain.entity.Member;
import com.gym.manage.domain.entity.MemberCard;
import com.gym.manage.domain.repository.MemberCardRepository;
import com.gym.manage.domain.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
@Slf4j
@Service
@RequiredArgsConstructor
public class MemberCardService {
private final MemberCardRepository memberCardRepository;
private final MemberRepository memberRepository;
public Mono<MemberCardResponse> createMemberCard(MemberCardCreateRequest request) {
log.info("创建会员卡: memberId={}, cardNo={}", request.getMemberId(), request.getCardNo());
return memberRepository.findByIdAndDeletedAtIsNull(request.getMemberId())
.switchIfEmpty(Mono.error(new BusinessException(ErrorCode.MEMBER_NOT_FOUND, "会员不存在")))
.flatMap(member -> memberCardRepository.findByCardNoAndDeletedAtIsNull(request.getCardNo()))
.flatMap(existingCard -> Mono.<MemberCard>error(
new BusinessException(ErrorCode.MEMBER_CARD_NOT_FOUND, "卡号已存在")
))
.switchIfEmpty(Mono.defer(() -> {
MemberCard card = new MemberCard();
card.setTenantId(request.getMemberId());
card.setStoreId(request.getMemberId());
card.setMemberId(request.getMemberId());
card.setCardNo(request.getCardNo());
card.setCardType(request.getCardType());
card.setCardName(request.getCardName());
card.setTotalCount(request.getTotalCount());
card.setRemainingCount(request.getTotalCount());
card.setTotalDays(request.getTotalDays());
card.setRemainingDays(request.getTotalDays());
card.setStartDate(request.getStartDate());
card.setEndDate(request.getEndDate());
card.setStatus("ACTIVE");
card.setPrice(request.getPrice());
card.setPaidAmount(request.getPaidAmount());
card.setPaymentMethod(request.getPaymentMethod());
card.setRemark(request.getRemark());
card.setCreatedAt(LocalDateTime.now());
card.setUpdatedAt(LocalDateTime.now());
return memberCardRepository.save(card);
}))
.map(this::toMemberCardResponse)
.doOnSuccess(response -> log.info("会员卡创建成功: cardId={}", response.getId()))
.doOnError(e -> log.error("会员卡创建失败: memberId={}, error={}", request.getMemberId(), e.getMessage()));
}
public Flux<MemberCardResponse> getMemberCards(Long memberId) {
log.info("查询会员卡列表: memberId={}", memberId);
return memberCardRepository.findByMemberIdAndDeletedAtIsNull(memberId)
.map(this::toMemberCardResponse);
}
private MemberCardResponse toMemberCardResponse(MemberCard card) {
return MemberCardResponse.builder()
.id(card.getId())
.memberId(card.getMemberId())
.cardNo(card.getCardNo())
.cardType(card.getCardType())
.cardName(card.getCardName())
.totalCount(card.getTotalCount())
.remainingCount(card.getRemainingCount())
.totalDays(card.getTotalDays())
.remainingDays(card.getRemainingDays())
.startDate(card.getStartDate())
.endDate(card.getEndDate())
.status(card.getStatus())
.price(card.getPrice())
.paidAmount(card.getPaidAmount())
.paymentMethod(card.getPaymentMethod())
.remark(card.getRemark())
.createdAt(card.getCreatedAt())
.updatedAt(card.getUpdatedAt())
.build();
}
}
@@ -0,0 +1,134 @@
package com.gym.manage.application.service;
import com.gym.manage.api.dto.request.MemberCreateRequest;
import com.gym.manage.api.dto.request.MemberUpdateRequest;
import com.gym.manage.api.dto.response.MemberResponse;
import com.gym.manage.common.constant.ErrorCode;
import com.gym.manage.common.exception.BusinessException;
import com.gym.manage.domain.entity.Member;
import com.gym.manage.domain.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
@Slf4j
@Service
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
public Mono<MemberResponse> createMember(MemberCreateRequest request) {
log.info("创建会员: phone={}", request.getPhone());
return memberRepository.findByPhoneAndDeletedAtIsNull(request.getPhone())
.flatMap(existingMember -> Mono.<Member>error(
new BusinessException(ErrorCode.MEMBER_ALREADY_EXISTS, "该手机号已注册")
))
.switchIfEmpty(Mono.defer(() -> {
Member member = new Member();
member.setTenantId(request.getTenantId());
member.setStoreId(request.getStoreId());
member.setName(request.getName());
member.setPhone(request.getPhone());
member.setGender(request.getGender());
member.setBirthday(request.getBirthday());
member.setIdCard(request.getIdCard());
member.setEmergencyContact(request.getEmergencyContact());
member.setEmergencyPhone(request.getEmergencyPhone());
member.setLevel(request.getLevel());
member.setStatus("ACTIVE");
member.setSource(request.getSource());
member.setRemark(request.getRemark());
member.setCreatedAt(LocalDateTime.now());
member.setUpdatedAt(LocalDateTime.now());
return memberRepository.save(member);
}))
.map(this::toMemberResponse)
.doOnSuccess(response -> log.info("会员创建成功: memberId={}", response.getId()))
.doOnError(e -> log.error("会员创建失败: phone={}, error={}", request.getPhone(), e.getMessage()));
}
public Mono<MemberResponse> getMember(Long id) {
log.info("查询会员: memberId={}", id);
return memberRepository.findByIdAndDeletedAtIsNull(id)
.switchIfEmpty(Mono.error(new BusinessException(ErrorCode.MEMBER_NOT_FOUND, "会员不存在")))
.map(this::toMemberResponse)
.doOnSuccess(response -> log.info("查询会员成功: memberId={}", id))
.doOnError(e -> log.error("查询会员失败: memberId={}, error={}", id, e.getMessage()));
}
public Flux<MemberResponse> listMembers(Long tenantId, Long storeId, int page, int size) {
log.info("查询会员列表: tenantId={}, storeId={}, page={}, size={}", tenantId, storeId, page, size);
return memberRepository.findByTenantIdAndStoreIdAndDeletedAtIsNull(
tenantId, storeId, PageRequest.of(page, size)
).map(this::toMemberResponse);
}
public Mono<MemberResponse> updateMember(Long id, MemberUpdateRequest request) {
log.info("更新会员: memberId={}", id);
return memberRepository.findByIdAndDeletedAtIsNull(id)
.switchIfEmpty(Mono.error(new BusinessException(ErrorCode.MEMBER_NOT_FOUND, "会员不存在")))
.flatMap(member -> {
member.setName(request.getName());
member.setGender(request.getGender());
member.setBirthday(request.getBirthday());
member.setIdCard(request.getIdCard());
member.setEmergencyContact(request.getEmergencyContact());
member.setEmergencyPhone(request.getEmergencyPhone());
member.setLevel(request.getLevel());
member.setStatus(request.getStatus());
member.setRemark(request.getRemark());
member.setUpdatedAt(LocalDateTime.now());
return memberRepository.save(member);
})
.map(this::toMemberResponse)
.doOnSuccess(response -> log.info("会员更新成功: memberId={}", id))
.doOnError(e -> log.error("会员更新失败: memberId={}, error={}", id, e.getMessage()));
}
public Mono<Void> deleteMember(Long id) {
log.info("删除会员: memberId={}", id);
return memberRepository.softDeleteById(id)
.flatMap(rows -> {
if (rows > 0) {
log.info("会员删除成功: memberId={}", id);
return Mono.empty();
} else {
return Mono.error(new BusinessException(ErrorCode.MEMBER_NOT_FOUND, "会员不存在"));
}
});
}
private MemberResponse toMemberResponse(Member member) {
return MemberResponse.builder()
.id(member.getId())
.tenantId(member.getTenantId())
.storeId(member.getStoreId())
.name(member.getName())
.phone(member.getPhone())
.gender(member.getGender())
.birthday(member.getBirthday())
.idCard(member.getIdCard())
.emergencyContact(member.getEmergencyContact())
.emergencyPhone(member.getEmergencyPhone())
.level(member.getLevel())
.status(member.getStatus())
.source(member.getSource())
.remark(member.getRemark())
.createdAt(member.getCreatedAt())
.updatedAt(member.getUpdatedAt())
.build();
}
}