add waitlist

pull/882/head
chanhengseang 2025-05-26 11:59:22 -07:00
parent 186b685ab5
commit 81c8c2cf4e
17 changed files with 866 additions and 12 deletions

View File

@ -1,4 +1,6 @@
-- Add tags column to event table
ALTER TABLE event
add column poster_image varchar(255),
ADD COLUMN tags VARCHAR(255) NULL COMMENT 'Tags stored as comma-delimited string';
ADD COLUMN poster_image VARCHAR(255),
ADD COLUMN tags VARCHAR(255) NULL COMMENT 'Tags stored as comma-delimited string',
ADD COLUMN current_participants INT DEFAULT 0 COMMENT 'Current number of participants',
ADD COLUMN max_participants INT NULL COMMENT 'Maximum number of participants';

View File

@ -0,0 +1,18 @@
-- Create wait list table for tracking players waiting to join events
CREATE TABLE IF NOT EXISTS wait_list (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
event_id BIGINT NOT NULL COMMENT 'Reference to event',
player_id BIGINT NOT NULL COMMENT 'Reference to player',
notes VARCHAR(255) NULL COMMENT 'Notes',
status VARCHAR(20) NOT NULL DEFAULT 'WAITING' COMMENT 'Status (WAITING, PROMOTED, CANCELLED, EXPIRED)',
create_time DATETIME NULL COMMENT 'Creation time',
update_time DATETIME NULL COMMENT 'Update time',
CONSTRAINT fk_wait_list_event FOREIGN KEY (event_id) REFERENCES event (id),
CONSTRAINT fk_wait_list_player FOREIGN KEY (player_id) REFERENCES player (id),
UNIQUE KEY uk_wait_list_event_player (event_id, player_id)
) ENGINE = InnoDB COMMENT 'Event wait list';
-- Add index for faster queries
CREATE INDEX idx_wait_list_event ON wait_list (event_id);
CREATE INDEX idx_wait_list_player ON wait_list (player_id);
CREATE INDEX idx_wait_list_status ON wait_list (status);

View File

@ -41,7 +41,6 @@ create table event
name varchar(32) not null comment '名称',
description varchar(255) null comment '描述',
format enum ('SINGLE', 'DOUBLE', 'TEAM') not null,
max_player int null comment '最大人数',
location varchar(255) null comment '位置',
image varchar(255) null comment '图片',
create_time datetime null comment '创建时间',

View File

@ -68,10 +68,6 @@ public class Event implements Serializable {
@ApiModelProperty(value = "SINGLE, DOUBLE")
private Format format;
@Column(name = "`max_player`")
@ApiModelProperty(value = "Maximum number of people")
private Integer maxPlayer;
@Column(name = "`location`")
@ApiModelProperty(value = "Location")
private String location;
@ -140,6 +136,14 @@ public class Event implements Serializable {
@Column(name = "`allow_wait_list`")
private boolean allowWaitList;
@Column(name = "`current_participants`")
@ApiModelProperty(value = "Current number of participants")
private Integer currentParticipants = 0;
@Column(name = "`max_participants`")
@ApiModelProperty(value = "Maximum number of participants")
private Integer maxParticipants;
@Column(name = "`poster_image`")
private String posterImage;

View File

@ -0,0 +1,85 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.srr.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.srr.enumeration.WaitListStatus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* Event Wait List Entity
* @author Chanheng
* @date 2025-05-26
*/
@Entity
@Getter
@Setter
@Accessors(chain = true)
@Table(name = "wait_list")
public class WaitList implements Serializable {
@Id
@Column(name = "id")
@ApiModelProperty(value = "ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "event_id", nullable = false)
@NotNull
@ApiModelProperty(value = "Event ID")
private Long eventId;
@Column(name = "player_id", nullable = false)
@NotNull
@ApiModelProperty(value = "Player ID")
private Long playerId;
@Column(name = "notes")
@ApiModelProperty(value = "Notes")
private String notes;
@Enumerated(EnumType.STRING)
@Column(name = "status")
@ApiModelProperty(value = "Status (WAITING, PROMOTED, CANCELLED, EXPIRED)")
private WaitListStatus status = WaitListStatus.WAITING;
@Column(name = "create_time")
@CreationTimestamp
@ApiModelProperty(value = "Creation Time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Timestamp createTime;
@Column(name = "update_time")
@UpdateTimestamp
@ApiModelProperty(value = "Update Time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Timestamp updateTime;
public void copy(WaitList source) {
this.notes = source.getNotes();
this.status = source.getStatus();
}
}

View File

@ -45,9 +45,6 @@ public class EventDto implements Serializable {
@ApiModelProperty(value = "SINGLE, DOUBLE")
private Format format;
@ApiModelProperty(value = "最大人数")
private Integer maxPlayer;
@ApiModelProperty(value = "位置")
private String location;
@ -95,6 +92,12 @@ public class EventDto implements Serializable {
private String posterImage;
@ApiModelProperty(value = "Current number of participants")
private Integer currentParticipants;
@ApiModelProperty(value = "Maximum number of participants")
private Integer maxParticipants;
@ApiModelProperty(value = "Co-host players")
private List<PlayerDto> coHostPlayers;

View File

@ -1,13 +1,43 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.srr.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* @author Chanheng
* @date 2025-05-26
*/
@Data
public class JoinEventDto {
private Long playerId;
@ApiModelProperty(value = "Event ID")
@NotNull
private Long eventId;
@ApiModelProperty(value = "Player ID")
@NotNull
private Long playerId;
@ApiModelProperty(value = "Team ID (optional)")
private Long teamId;
@ApiModelProperty(value = "Join as wait list")
private Boolean joinWaitList = false;
}

View File

@ -0,0 +1,65 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.srr.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.srr.enumeration.WaitListStatus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* @author Chanheng
* @date 2025-05-26
* @description Wait list DTO for transferring wait list data
*/
@Getter
@Setter
public class WaitListDto implements Serializable {
@ApiModelProperty(value = "id")
private Long id;
@ApiModelProperty(value = "Event ID")
private Long eventId;
@ApiModelProperty(value = "Player ID")
private Long playerId;
@ApiModelProperty(value = "Notes")
private String notes;
@ApiModelProperty(value = "Status (WAITING, PROMOTED, CANCELLED, EXPIRED)")
private WaitListStatus status;
@ApiModelProperty(value = "Creation time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Timestamp createTime;
@ApiModelProperty(value = "Update time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Timestamp updateTime;
// Additional relationships can be added if needed
@ApiModelProperty(value = "Player")
private PlayerDto player;
@ApiModelProperty(value = "Event")
private EventDto event;
}

View File

@ -0,0 +1,51 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.srr.dto;
import com.srr.enumeration.WaitListStatus;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import me.zhengjie.annotation.Query;
import java.sql.Timestamp;
import java.util.List;
/**
* @author Chanheng
* @date 2025-05-26
*/
@Data
public class WaitListQueryCriteria {
@Query
private Long id;
@Query
@ApiModelProperty(value = "Event ID")
private Long eventId;
@Query
@ApiModelProperty(value = "Player ID")
private Long playerId;
@Query
@ApiModelProperty(value = "Status")
private WaitListStatus status;
@Query(type = Query.Type.BETWEEN)
@ApiModelProperty(value = "Create time range")
private List<Timestamp> createTime;
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.srr.enumeration;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Enum representing the possible states of a wait list entry
* @author Chanheng
* @date 2025-05-26
*/
@Getter
@AllArgsConstructor
public enum WaitListStatus {
WAITING("Waiting"),
PROMOTED("Promoted to participant"),
CANCELLED("Cancelled by player"),
EXPIRED("Expired due to event start");
private final String description;
}

View File

@ -0,0 +1,66 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.srr.repository;
import com.srr.domain.WaitList;
import com.srr.enumeration.WaitListStatus;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import java.util.List;
/**
* @author Chanheng
* @date 2025-05-26
*/
public interface WaitListRepository extends JpaRepository<WaitList, Long>, JpaSpecificationExecutor<WaitList> {
/**
* Find all wait list entries for an event
* @param eventId The event ID
* @return List of wait list entries
*/
List<WaitList> findByEventId(Long eventId);
/**
* Find all wait list entries for a player
* @param playerId The player ID
* @return List of wait list entries
*/
List<WaitList> findByPlayerId(Long playerId);
/**
* Find wait list entry for a specific player and event
* @param eventId The event ID
* @param playerId The player ID
* @return WaitList entry if exists
*/
WaitList findByEventIdAndPlayerId(Long eventId, Long playerId);
/**
* Find wait list entries by status
* @param status The status (WAITING, PROMOTED, CANCELLED, EXPIRED)
* @return List of wait list entries
*/
List<WaitList> findByStatus(WaitListStatus status);
/**
* Count wait list entries for an event
* @param eventId The event ID
* @return Count of wait list entries
*/
long countByEventId(Long eventId);
}

View File

@ -93,7 +93,13 @@ public class EventController {
return new ResponseEntity<>(result, HttpStatus.OK);
}
@PostMapping("/{id}/join")
@Log("Join event")
@ApiOperation("Join event")
@PreAuthorize("@el.check('event:join')")
public ResponseEntity<Object> joinEvent(@PathVariable Long id, @RequestBody JoinEventDto joinEventDto) {
// Ensure ID in path matches ID in DTO
joinEventDto.setEventId(id);
final EventDto result = eventService.joinEvent(joinEventDto);
return new ResponseEntity<>(result, HttpStatus.OK);
}

View File

@ -0,0 +1,108 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.srr.rest;
import com.srr.domain.WaitList;
import com.srr.dto.WaitListDto;
import com.srr.dto.WaitListQueryCriteria;
import com.srr.service.WaitListService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import me.zhengjie.utils.PageResult;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
* @author Chanheng
* @date 2025-05-26
*/
@RestController
@RequiredArgsConstructor
@Api(tags = "Wait List Management")
@RequestMapping("/api/wait-list")
public class WaitListController {
private final WaitListService waitListService;
private static final String ENTITY_NAME = "waitList";
@ApiOperation("Export wait list data")
@GetMapping(value = "/download")
@PreAuthorize("@el.check('waitList:list')")
public void exportWaitList(HttpServletResponse response, WaitListQueryCriteria criteria) throws IOException {
waitListService.download(waitListService.queryAll(criteria), response);
}
@ApiOperation("Query wait list entries")
@GetMapping
@PreAuthorize("@el.check('waitList:list')")
public ResponseEntity<PageResult<WaitListDto>> queryWaitList(WaitListQueryCriteria criteria, Pageable pageable) {
return new ResponseEntity<>(waitListService.queryAll(criteria, pageable), HttpStatus.OK);
}
@ApiOperation("Query wait list entries by event ID")
@GetMapping(value = "/event/{eventId}")
@PreAuthorize("@el.check('waitList:list')")
public ResponseEntity<List<WaitListDto>> queryWaitListByEvent(@PathVariable Long eventId) {
return new ResponseEntity<>(waitListService.findByEventId(eventId), HttpStatus.OK);
}
@ApiOperation("Query wait list entries by player ID")
@GetMapping(value = "/player/{playerId}")
@PreAuthorize("@el.check('waitList:list')")
public ResponseEntity<List<WaitListDto>> queryWaitListByPlayer(@PathVariable Long playerId) {
return new ResponseEntity<>(waitListService.findByPlayerId(playerId), HttpStatus.OK);
}
@ApiOperation("Add to wait list")
@PostMapping
@PreAuthorize("@el.check('waitList:add')")
public ResponseEntity<WaitListDto> createWaitList(@Validated @RequestBody WaitList resources) {
return new ResponseEntity<>(waitListService.create(resources), HttpStatus.CREATED);
}
@ApiOperation("Update wait list entry")
@PutMapping
@PreAuthorize("@el.check('waitList:edit')")
public ResponseEntity<Object> updateWaitList(@Validated @RequestBody WaitList resources) {
waitListService.update(resources);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@ApiOperation("Promote player from wait list to participant")
@PutMapping(value = "/{id}/promote")
@PreAuthorize("@el.check('waitList:edit')")
public ResponseEntity<Object> promoteWaitListEntry(@PathVariable Long id) {
boolean success = waitListService.promoteToParticipant(id);
return new ResponseEntity<>(success ? HttpStatus.OK : HttpStatus.BAD_REQUEST);
}
@ApiOperation("Delete wait list entry")
@DeleteMapping(value = "/{id}")
@PreAuthorize("@el.check('waitList:del')")
public ResponseEntity<Object> deleteWaitList(@PathVariable Long id) {
waitListService.delete(id);
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@ -18,6 +18,7 @@ package com.srr.service;
import com.srr.domain.Event;
import com.srr.dto.EventDto;
import com.srr.dto.EventQueryCriteria;
import com.srr.dto.JoinEventDto;
import com.srr.enumeration.EventStatus;
import org.springframework.data.domain.Pageable;
@ -70,6 +71,13 @@ public interface EventService {
EventDto updateStatus(Long id, EventStatus status);
/**
* Join an event
* @param joinEventDto Data for joining an event
* @return Updated event data
*/
EventDto joinEvent(JoinEventDto joinEventDto);
/**
* Multi-select delete
* @param ids /

View File

@ -0,0 +1,118 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.srr.service;
import com.srr.domain.WaitList;
import com.srr.dto.WaitListDto;
import com.srr.dto.WaitListQueryCriteria;
import me.zhengjie.utils.PageResult;
import org.springframework.data.domain.Pageable;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* @author Chanheng
* @date 2025-05-26
*/
public interface WaitListService {
/**
* Add a player to the wait list
* @param waitList Player wait list entry
* @return Created wait list entry
*/
WaitListDto create(WaitList waitList);
/**
* Update wait list entry
* @param waitList Updated wait list entry
*/
void update(WaitList waitList);
/**
* Delete wait list entry
* @param id Wait list entry ID
*/
void delete(Long id);
/**
* Delete multiple wait list entries
* @param ids List of wait list entry IDs
*/
void deleteAll(List<Long> ids);
/**
* Find a wait list entry by ID
* @param id Wait list entry ID
* @return Wait list entry
*/
WaitListDto findById(Long id);
/**
* Find wait list entries by event ID
* @param eventId Event ID
* @return List of wait list entries
*/
List<WaitListDto> findByEventId(Long eventId);
/**
* Find wait list entries by player ID
* @param playerId Player ID
* @return List of wait list entries
*/
List<WaitListDto> findByPlayerId(Long playerId);
/**
* Find wait list entry for a specific player and event
* @param eventId Event ID
* @param playerId Player ID
* @return Wait list entry
*/
WaitListDto findByEventAndPlayer(Long eventId, Long playerId);
/**
* Promote a player from wait list to event participant
* @param waitListId Wait list entry ID
* @return True if promotion successful
*/
boolean promoteToParticipant(Long waitListId);
/**
* Query wait list with criteria
* @param criteria Query criteria
* @param pageable Pagination information
* @return Page result with wait list entries
*/
PageResult<WaitListDto> queryAll(WaitListQueryCriteria criteria, Pageable pageable);
/**
* Query all wait list entries
* @param criteria Query criteria
* @return List of wait list entries
*/
List<WaitListDto> queryAll(WaitListQueryCriteria criteria);
/**
* Export wait list data
* @param queryAll All wait list entries
* @param response HTTP response
* @throws IOException If export fails
*/
void download(List<WaitListDto> queryAll, HttpServletResponse response) throws IOException;
}

View File

@ -26,6 +26,10 @@ import com.srr.service.EventService;
import com.srr.dto.EventDto;
import com.srr.dto.EventQueryCriteria;
import com.srr.dto.mapstruct.EventMapper;
import com.srr.dto.JoinEventDto;
import com.srr.repository.TeamPlayerRepository;
import com.srr.repository.TeamRepository;
import me.zhengjie.exception.BadRequestException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
@ -56,6 +60,8 @@ public class EventServiceImpl implements EventService {
private final EventRepository eventRepository;
private final EventMapper eventMapper;
private final TeamRepository teamRepository;
private final TeamPlayerRepository teamPlayerRepository;
@Override
public PageResult<EventDto> queryAll(EventQueryCriteria criteria, Pageable pageable) {
@ -110,6 +116,50 @@ public class EventServiceImpl implements EventService {
return eventMapper.toDto(result);
}
@Override
@Transactional(rollbackFor = Exception.class)
public EventDto joinEvent(JoinEventDto joinEventDto) {
// Find the event
Event event = eventRepository.findById(joinEventDto.getEventId())
.orElseThrow(() -> new EntityNotFoundException(Event.class, "id", joinEventDto.getEventId()));
// Check if event allows joining
if (event.getStatus() != EventStatus.OPEN) {
throw new BadRequestException("Event is not open for joining");
}
// Check if event is full and handle waitlist
boolean isWaitList = joinEventDto.getJoinWaitList() != null && joinEventDto.getJoinWaitList();
if (event.getMaxParticipants() != null &&
event.getCurrentParticipants() >= event.getMaxParticipants() &&
!isWaitList) {
if (!event.isAllowWaitList()) {
throw new BadRequestException("Event is full and does not allow waitlist");
}
// Set joinWaitList to true if event is full and waitlist is allowed
isWaitList = true;
}
// Handle team-related logic
if (joinEventDto.getTeamId() != null) {
// Add player to existing team
// For implementation, you'd use teamRepository and teamPlayerRepository
// to check if team exists and add the player
} else {
// Create new team for the player if needed
// or add as individual participant depending on event format
}
// Update participant count if not joining waitlist
if (!isWaitList) {
event.setCurrentParticipants(event.getCurrentParticipants() + 1);
}
// Save and return updated event
final var result = eventRepository.save(event);
return eventMapper.toDto(result);
}
@Override
public void deleteAll(Long[] ids) {
for (Long id : ids) {
@ -125,7 +175,6 @@ public class EventServiceImpl implements EventService {
map.put("名称", event.getName());
map.put("描述", event.getDescription());
map.put("SINGLE, DOUBLE", event.getFormat());
map.put("最大人数", event.getMaxPlayer());
map.put("位置", event.getLocation());
map.put("图片", event.getImage());
map.put("创建时间", event.getCreateTime());

View File

@ -0,0 +1,206 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.srr.service.impl;
import com.srr.domain.Event;
import com.srr.domain.WaitList;
import com.srr.enumeration.WaitListStatus;
import com.srr.dto.WaitListDto;
import com.srr.dto.WaitListQueryCriteria;
import com.srr.repository.EventRepository;
import com.srr.repository.WaitListRepository;
import com.srr.service.WaitListService;
import lombok.RequiredArgsConstructor;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.exception.EntityNotFoundException;
import me.zhengjie.utils.FileUtil;
import me.zhengjie.utils.PageUtil;
import me.zhengjie.utils.QueryHelp;
import me.zhengjie.utils.PageResult;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Chanheng
* @date 2025-05-26
*/
@Service
@RequiredArgsConstructor
public class WaitListServiceImpl implements WaitListService {
private final WaitListRepository waitListRepository;
private final EventRepository eventRepository;
@Override
@Transactional
public WaitListDto create(WaitList resources) {
// Validate event exists
Event event = eventRepository.findById(resources.getEventId())
.orElseThrow(() -> new EntityNotFoundException(Event.class, "id", resources.getEventId()));
// Check if player is already in wait list
if (waitListRepository.findByEventIdAndPlayerId(resources.getEventId(), resources.getPlayerId()) != null) {
throw new BadRequestException("Player is already in wait list");
}
// Set default status
resources.setStatus(WaitListStatus.WAITING);
return mapToDto(waitListRepository.save(resources));
}
@Override
@Transactional
public void update(WaitList resources) {
WaitList waitList = waitListRepository.findById(resources.getId())
.orElseThrow(() -> new EntityNotFoundException(WaitList.class, "id", resources.getId()));
waitList.copy(resources);
waitListRepository.save(waitList);
}
@Override
@Transactional
public void delete(Long id) {
waitListRepository.deleteById(id);
}
@Override
@Transactional
public void deleteAll(List<Long> ids) {
waitListRepository.deleteAllById(ids);
}
@Override
public WaitListDto findById(Long id) {
WaitList waitList = waitListRepository.findById(id)
.orElseThrow(() -> new EntityNotFoundException(WaitList.class, "id", id));
return mapToDto(waitList);
}
@Override
public List<WaitListDto> findByEventId(Long eventId) {
// Validate event exists
if (!eventRepository.existsById(eventId)) {
throw new EntityNotFoundException(Event.class, "id", eventId);
}
return waitListRepository.findByEventId(eventId).stream()
.map(this::mapToDto)
.collect(Collectors.toList());
}
@Override
public List<WaitListDto> findByPlayerId(Long playerId) {
return waitListRepository.findByPlayerId(playerId).stream()
.map(this::mapToDto)
.collect(Collectors.toList());
}
@Override
public WaitListDto findByEventAndPlayer(Long eventId, Long playerId) {
WaitList waitList = waitListRepository.findByEventIdAndPlayerId(eventId, playerId);
return waitList != null ? mapToDto(waitList) : null;
}
@Override
@Transactional
public boolean promoteToParticipant(Long waitListId) {
// Find wait list entry
WaitList waitList = waitListRepository.findById(waitListId)
.orElseThrow(() -> new EntityNotFoundException(WaitList.class, "id", waitListId));
// Find event
Event event = eventRepository.findById(waitList.getEventId())
.orElseThrow(() -> new EntityNotFoundException(Event.class, "id", waitList.getEventId()));
// Check if event is full
if (event.getCurrentParticipants() >= event.getMaxParticipants()) {
return false;
}
// Update wait list status
waitList.setStatus(WaitListStatus.PROMOTED);
waitListRepository.save(waitList);
// Increment participant count
event.setCurrentParticipants(event.getCurrentParticipants() + 1);
eventRepository.save(event);
// TODO: Add player to event participants (implementation depends on your data model)
return true;
}
@Override
public PageResult<WaitListDto> queryAll(WaitListQueryCriteria criteria, Pageable pageable) {
Page<WaitList> page = waitListRepository.findAll((root, criteriaQuery, criteriaBuilder) ->
QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);
return PageUtil.toPage(page.map(this::mapToDto));
}
@Override
public List<WaitListDto> queryAll(WaitListQueryCriteria criteria) {
return waitListRepository.findAll((root, criteriaQuery, criteriaBuilder) ->
QueryHelp.getPredicate(root, criteria, criteriaBuilder))
.stream()
.map(this::mapToDto)
.collect(Collectors.toList());
}
@Override
public void download(List<WaitListDto> queryAll, HttpServletResponse response) throws IOException {
List<Map<String, Object>> list = new ArrayList<>();
for (WaitListDto waitList : queryAll) {
Map<String, Object> map = new LinkedHashMap<>();
map.put("Event ID", waitList.getEventId());
map.put("Player ID", waitList.getPlayerId());
map.put("Status", waitList.getStatus() != null ? waitList.getStatus().getDescription() : null);
map.put("Notes", waitList.getNotes());
map.put("Creation Time", waitList.getCreateTime());
list.add(map);
}
FileUtil.downloadExcel(list, response);
}
/**
* Map entity to DTO
*/
private WaitListDto mapToDto(WaitList waitList) {
if (waitList == null) {
return null;
}
WaitListDto dto = new WaitListDto();
dto.setId(waitList.getId());
dto.setEventId(waitList.getEventId());
dto.setPlayerId(waitList.getPlayerId());
dto.setNotes(waitList.getNotes());
dto.setStatus(waitList.getStatus());
dto.setCreateTime(waitList.getCreateTime());
dto.setUpdateTime(waitList.getUpdateTime());
// Load relationships if needed (can be implemented based on requirements)
return dto;
}
}