Merge pull request #7 from sports-match/add-field-in-event

Add field in event
pull/882/head
Chanheng 2025-05-26 12:03:33 -07:00 committed by GitHub
commit e8aee9751b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
37 changed files with 1796 additions and 80 deletions

View File

@ -23,12 +23,16 @@ import org.springframework.util.StringUtils;
*/ */
public class EntityNotFoundException extends RuntimeException { public class EntityNotFoundException extends RuntimeException {
public EntityNotFoundException(Class clazz, String field, String val) { public EntityNotFoundException(Class<?> clazz, String field, String val) {
super(EntityNotFoundException.generateMessage(clazz.getSimpleName(), field, val)); super(EntityNotFoundException.generateMessage(clazz.getSimpleName(), field, val));
} }
public EntityNotFoundException(Class<?> clazz, String field, Long val) {
super(EntityNotFoundException.generateMessage(clazz.getSimpleName(), field, "" + val));
}
private static String generateMessage(String entity, String field, String val) { private static String generateMessage(String entity, String field, String val) {
return StringUtils.capitalize(entity) return StringUtils.capitalize(entity)
+ " with " + field + " "+ val + " does not exist"; + " with " + field + " " + val + " does not exist";
} }
} }

View File

@ -0,0 +1,26 @@
-- Add rating_history table
CREATE TABLE rating_history
(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
player_id BIGINT NOT NULL COMMENT 'Player ID',
rate_score DOUBLE NULL COMMENT 'Rating score',
changes DOUBLE NULL COMMENT 'Score changes',
create_time TIMESTAMP NULL COMMENT 'Creation time',
match_id BIGINT NULL COMMENT 'Match ID',
CONSTRAINT fk_rating_history_player FOREIGN KEY (player_id) REFERENCES player (id),
CONSTRAINT fk_rating_history_match FOREIGN KEY (match_id) REFERENCES `match` (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'Rating History';
-- Create index for fast lookup by player and match
CREATE INDEX idx_rating_history_player ON rating_history (player_id);
CREATE INDEX idx_rating_history_match ON rating_history (match_id);
-- Update event_organizer table with additional fields
ALTER TABLE event_organizer
ADD COLUMN description VARCHAR(255) NULL COMMENT 'Description',
ADD COLUMN create_time TIMESTAMP NULL COMMENT 'Creation time',
ADD COLUMN update_time TIMESTAMP NULL COMMENT 'Update time';
-- Create index for faster lookup by user_id
CREATE INDEX idx_event_organizer_user ON event_organizer (user_id);

View File

@ -0,0 +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 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 '名称', name varchar(32) not null comment '名称',
description varchar(255) null comment '描述', description varchar(255) null comment '描述',
format enum ('SINGLE', 'DOUBLE', 'TEAM') not null, format enum ('SINGLE', 'DOUBLE', 'TEAM') not null,
max_player int null comment '最大人数',
location varchar(255) null comment '位置', location varchar(255) null comment '位置',
image varchar(255) null comment '图片', image varchar(255) null comment '图片',
create_time datetime null comment '创建时间', create_time datetime null comment '创建时间',

View File

@ -0,0 +1,4 @@
-- Add check_in_at and group_count columns to event table
ALTER TABLE event
ADD COLUMN check_in_at TIMESTAMP NULL COMMENT 'Check-in time',
ADD COLUMN group_count INT NULL COMMENT 'Number of groups';

View File

@ -29,7 +29,7 @@
<logback.version>1.2.9</logback.version> <logback.version>1.2.9</logback.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version> <java.version>17</java.version>
<fastjson2.version>2.0.54</fastjson2.version> <fastjson2.version>2.0.54</fastjson2.version>
<druid.version>1.2.19</druid.version> <druid.version>1.2.19</druid.version>
<commons-pool2.version>2.11.1</commons-pool2.version> <commons-pool2.version>2.11.1</commons-pool2.version>

View File

@ -0,0 +1,49 @@
/*
* 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.converter;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Converter to store List<String> as a comma-delimited string in database
* @author Chanheng
* @date 2025-05-26
*/
@Converter
public class StringListConverter implements AttributeConverter<List<String>, String> {
private static final String DELIMITER = ",";
@Override
public String convertToDatabaseColumn(List<String> stringList) {
if (stringList == null || stringList.isEmpty()) {
return null;
}
return String.join(DELIMITER, stringList);
}
@Override
public List<String> convertToEntityAttribute(String string) {
if (string == null || string.isEmpty()) {
return new ArrayList<>();
}
return new ArrayList<>(Arrays.asList(string.split(DELIMITER)));
}
}

View File

@ -15,6 +15,7 @@
*/ */
package com.srr.domain; package com.srr.domain;
import com.srr.converter.StringListConverter;
import com.srr.enumeration.EventStatus; import com.srr.enumeration.EventStatus;
import com.srr.enumeration.Format; import com.srr.enumeration.Format;
import lombok.Data; import lombok.Data;
@ -24,6 +25,7 @@ import cn.hutool.core.bean.copier.CopyOptions;
import javax.persistence.*; import javax.persistence.*;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.Convert;
import org.hibernate.annotations.*; import org.hibernate.annotations.*;
import java.sql.Timestamp; import java.sql.Timestamp;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
@ -41,6 +43,8 @@ import java.util.List;
@Entity @Entity
@Data @Data
@Table(name="event") @Table(name="event")
@SQLDelete(sql = "update event set status = 'DELETED' where id = ?", check = ResultCheckStyle.COUNT)
@Where(clause = "status != 'DELETED'")
public class Event implements Serializable { public class Event implements Serializable {
@Id @Id
@ -64,10 +68,6 @@ public class Event implements Serializable {
@ApiModelProperty(value = "SINGLE, DOUBLE") @ApiModelProperty(value = "SINGLE, DOUBLE")
private Format format; private Format format;
@Column(name = "`max_player`")
@ApiModelProperty(value = "Maximum number of people")
private Integer maxPlayer;
@Column(name = "`location`") @Column(name = "`location`")
@ApiModelProperty(value = "Location") @ApiModelProperty(value = "Location")
private String location; private String location;
@ -86,6 +86,14 @@ public class Event implements Serializable {
@ApiModelProperty(value = "Update time", hidden = true) @ApiModelProperty(value = "Update time", hidden = true)
private Timestamp updateTime; private Timestamp updateTime;
@Column(name = "`check_in_at`")
@ApiModelProperty(value = "Check in time", hidden = true)
private Timestamp checkInAt;
@Column(name = "`group_count`")
@ApiModelProperty(value = "Number of groups")
private Integer groupCount;
@Column(name = "`sort`") @Column(name = "`sort`")
@ApiModelProperty(value = "Sort") @ApiModelProperty(value = "Sort")
private Integer sort; private Integer sort;
@ -128,6 +136,21 @@ public class Event implements Serializable {
@Column(name = "`allow_wait_list`") @Column(name = "`allow_wait_list`")
private boolean allowWaitList; 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;
@Column(name = "`tags`")
@Convert(converter = StringListConverter.class)
private List<String> tags = new ArrayList<>();
@ManyToMany @ManyToMany
@JoinTable(name = "event_co_host_player", @JoinTable(name = "event_co_host_player",
joinColumns = {@JoinColumn(name = "event_id",referencedColumnName = "id")}, joinColumns = {@JoinColumn(name = "event_id",referencedColumnName = "id")},

View File

@ -0,0 +1,74 @@
/*
* 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 lombok.Data;
import cn.hutool.core.bean.BeanUtil;
import io.swagger.annotations.ApiModelProperty;
import cn.hutool.core.bean.copier.CopyOptions;
import javax.persistence.*;
import javax.persistence.Entity;
import javax.persistence.Table;
import org.hibernate.annotations.*;
import java.sql.Timestamp;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* @website https://eladmin.vip
* @description Event organizer entity
* @author Chanheng
* @date 2025-05-26
**/
@Entity
@Data
@Table(name="event_organizer")
public class EventOrganizer implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "`id`")
@ApiModelProperty(value = "id", hidden = true)
private Long id;
@Column(name = "`description`")
@ApiModelProperty(value = "Description")
private String description;
@Column(name = "`create_time`")
@CreationTimestamp
@ApiModelProperty(value = "Creation time", hidden = true)
private Timestamp createTime;
@Column(name = "`update_time`")
@UpdateTimestamp
@ApiModelProperty(value = "Update time", hidden = true)
private Timestamp updateTime;
@Column(name = "`user_id`", nullable = false)
@NotNull
@ApiModelProperty(value = "userId")
private Long userId;
@ManyToOne
@JoinColumn(name = "club_id")
private Club club;
public void copy(EventOrganizer source){
BeanUtil.copyProperties(source, this, CopyOptions.create().setIgnoreNullValue(true));
}
}

View File

@ -0,0 +1,43 @@
package com.srr.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
@Getter
@Setter
@Entity
public class RatingHistory implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "`id`")
@ApiModelProperty(value = "id", hidden = true)
private Long id;
@ManyToOne
@JoinColumn(name = "player_id")
private Player player;
@Column(name = "`rate_score`")
@ApiModelProperty(value = "Score")
private Double rateScore;
@Column(name = "`changes`")
@ApiModelProperty(value = "Changes")
private Double changes;
@Column(name = "`create_time`")
@CreationTimestamp
@ApiModelProperty(value = "Creation time", hidden = true)
private Timestamp createTime;
@ManyToOne
@JoinColumn(name = "match_id")
private Match match;
}

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") @ApiModelProperty(value = "SINGLE, DOUBLE")
private Format format; private Format format;
@ApiModelProperty(value = "最大人数")
private Integer maxPlayer;
@ApiModelProperty(value = "位置") @ApiModelProperty(value = "位置")
private String location; private String location;
@ -87,6 +84,23 @@ public class EventDto implements Serializable {
private boolean allowWaitList; private boolean allowWaitList;
@ApiModelProperty(value = "Check-in time")
private Timestamp checkInAt;
@ApiModelProperty(value = "Number of groups")
private Integer groupCount;
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") @ApiModelProperty(value = "Co-host players")
private List<PlayerDto> coHostPlayers; private List<PlayerDto> coHostPlayers;
@ApiModelProperty(value = "Tags")
private List<String> tags;
} }

View File

@ -0,0 +1,50 @@
/*
* 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 java.io.Serializable;
import java.sql.Timestamp;
/**
* @website https://eladmin.vip
* @description Event organizer data transfer object
* @author Chanheng
* @date 2025-05-26
**/
@Data
public class EventOrganizerDto implements Serializable {
@ApiModelProperty(value = "id")
private Long id;
@ApiModelProperty(value = "Club")
private ClubDto club;
@ApiModelProperty(value = "Description")
private String description;
@ApiModelProperty(value = "Creation time")
private Timestamp createTime;
@ApiModelProperty(value = "Update time")
private Timestamp updateTime;
@ApiModelProperty(value = "User ID")
private Long userId;
}

View File

@ -0,0 +1,46 @@
/*
* 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 me.zhengjie.annotation.Query;
import java.sql.Timestamp;
import java.util.List;
/**
* @author Chanheng
* @date 2025-05-26
*/
@Data
public class EventOrganizerQueryCriteria {
@Query
private Long id;
@Query
@ApiModelProperty(value = "Event ID")
private Long eventId;
@Query
@ApiModelProperty(value = "Organizer User ID")
private Long userId;
@Query(type = Query.Type.BETWEEN)
@ApiModelProperty(value = "Create time range")
private List<Timestamp> createTime;
}

View File

@ -0,0 +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 {
@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,50 @@
/*
* 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 me.zhengjie.annotation.Query;
import java.sql.Timestamp;
import java.util.List;
/**
* @author Chanheng
* @date 2025-05-26
*/
@Data
public class MatchGroupQueryCriteria {
@Query
private Long id;
@Query
@ApiModelProperty(value = "Event ID")
private Long eventId;
@Query
@ApiModelProperty(value = "Group Name")
private String name;
@Query
@ApiModelProperty(value = "Group Number")
private Integer groupNumber;
@Query(type = Query.Type.BETWEEN)
@ApiModelProperty(value = "Create time range")
private List<Timestamp> createTime;
}

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.dto;
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 MatchQueryCriteria {
@Query
private Long id;
@Query
@ApiModelProperty(value = "Event ID")
private Long eventId;
@Query
@ApiModelProperty(value = "Match Group ID")
private Long matchGroupId;
@Query
@ApiModelProperty(value = "Team A ID")
private Long teamAId;
@Query
@ApiModelProperty(value = "Team B ID")
private Long teamBId;
@Query
@ApiModelProperty(value = "Court Number")
private Integer courtNumber;
@Query
@ApiModelProperty(value = "Match Status")
private String status;
@Query(type = Query.Type.BETWEEN)
@ApiModelProperty(value = "Match Time Range")
private List<Timestamp> matchTime;
@Query(type = Query.Type.BETWEEN)
@ApiModelProperty(value = "Create time range")
private List<Timestamp> createTime;
}

View File

@ -0,0 +1,53 @@
/*
* 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 java.io.Serializable;
import java.sql.Timestamp;
/**
* @website https://eladmin.vip
* @description /
* @author Chanheng
* @date 2025-05-26
**/
@Data
public class RatingHistoryDto implements Serializable {
@ApiModelProperty(value = "id")
private Long id;
@ApiModelProperty(value = "Player ID")
private Long playerId;
@ApiModelProperty(value = "Player name")
private String playerName;
@ApiModelProperty(value = "Rating score")
private Double rateScore;
@ApiModelProperty(value = "Score changes")
private Double changes;
@ApiModelProperty(value = "Creation time")
private Timestamp createTime;
@ApiModelProperty(value = "Match ID")
private Long matchId;
}

View File

@ -0,0 +1,54 @@
/*
* 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 me.zhengjie.annotation.Query;
import java.sql.Timestamp;
import java.util.List;
/**
* @author Chanheng
* @date 2025-05-26
*/
@Data
public class RatingHistoryQueryCriteria {
@Query
private Long id;
@Query
@ApiModelProperty(value = "Player ID")
private Long playerId;
@Query
@ApiModelProperty(value = "Sport ID")
private Long sportId;
@Query
@ApiModelProperty(value = "Event ID")
private Long eventId;
@Query(type = Query.Type.BETWEEN)
@ApiModelProperty(value = "Rating Range")
private List<Integer> rating;
@Query(type = Query.Type.BETWEEN)
@ApiModelProperty(value = "Create time range")
private List<Timestamp> createTime;
}

View File

@ -0,0 +1,50 @@
/*
* 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 me.zhengjie.annotation.Query;
import java.sql.Timestamp;
import java.util.List;
/**
* @author Chanheng
* @date 2025-05-26
*/
@Data
public class TeamPlayerQueryCriteria {
@Query
private Long id;
@Query
@ApiModelProperty(value = "Team ID")
private Long teamId;
@Query
@ApiModelProperty(value = "Player ID")
private Long playerId;
@Query
@ApiModelProperty(value = "Event ID")
private Long eventId;
@Query(type = Query.Type.BETWEEN)
@ApiModelProperty(value = "Create time range")
private List<Timestamp> createTime;
}

View File

@ -0,0 +1,46 @@
/*
* 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 me.zhengjie.annotation.Query;
import java.sql.Timestamp;
import java.util.List;
/**
* @author Chanheng
* @date 2025-05-26
*/
@Data
public class TeamQueryCriteria {
@Query
private Long id;
@Query
@ApiModelProperty(value = "Event ID")
private Long eventId;
@Query
@ApiModelProperty(value = "Team Name")
private String name;
@Query(type = Query.Type.BETWEEN)
@ApiModelProperty(value = "Create time range")
private List<Timestamp> createTime;
}

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,32 @@
/*
* 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.mapstruct;
import me.zhengjie.base.BaseMapper;
import com.srr.domain.EventOrganizer;
import com.srr.dto.EventOrganizerDto;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ReportingPolicy;
/**
* @website https://eladmin.vip
* @author Chanheng
* @date 2025-05-26
**/
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface EventOrganizerMapper extends BaseMapper<EventOrganizerDto, EventOrganizer> {
}

View File

@ -0,0 +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.mapstruct;
import me.zhengjie.base.BaseMapper;
import com.srr.domain.RatingHistory;
import com.srr.dto.RatingHistoryDto;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ReportingPolicy;
/**
* @website https://eladmin.vip
* @author Chanheng
* @date 2025-05-26
**/
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface RatingHistoryMapper extends BaseMapper<RatingHistoryDto, RatingHistory> {
/**
* Entity to DTO mapping with explicit field mappings
* @param entity RatingHistory entity
* @return RatingHistoryDto
*/
@Override
@Mapping(source = "player.id", target = "playerId")
@Mapping(source = "player.name", target = "playerName")
@Mapping(source = "match.id", target = "matchId")
RatingHistoryDto toDto(RatingHistory entity);
}

View File

@ -1,7 +1,10 @@
package com.srr.enumeration; package com.srr.enumeration;
public enum EventStatus { public enum EventStatus {
DRAFT,
OPEN, OPEN,
CHECK_IN,
IN_PROGRESS, IN_PROGRESS,
CLOSED CLOSED,
DELETED
} }

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,39 @@
/*
* 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.EventOrganizer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @website https://eladmin.vip
* @author Chanheng
* @date 2025-05-26
**/
@Repository
public interface EventOrganizerRepository extends JpaRepository<EventOrganizer, Long>, JpaSpecificationExecutor<EventOrganizer> {
/**
* Find event organizers by user id
* @param userId the user id
* @return list of event organizers
*/
List<EventOrganizer> findByUserId(Long userId);
}

View File

@ -0,0 +1,34 @@
/*
* 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.RatingHistory;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @website https://eladmin.vip
* @author Chanheng
* @date 2025-05-26
**/
@Repository
public interface RatingHistoryRepository extends JpaRepository<RatingHistory, Long>, JpaSpecificationExecutor<RatingHistory> {
List<RatingHistory> findByPlayerIdOrderByCreateTimeDesc(Long playerId);
}

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

@ -1,42 +1,47 @@
/* /*
* Copyright 2019-2025 Zheng Jie * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.srr.rest; package com.srr.rest;
import me.zhengjie.annotation.Log;
import com.srr.domain.Event; import com.srr.domain.Event;
import com.srr.service.EventService; import com.srr.dto.EventDto;
import com.srr.dto.EventQueryCriteria; import com.srr.dto.EventQueryCriteria;
import org.springframework.data.domain.Pageable; import com.srr.dto.JoinEventDto;
import com.srr.enumeration.EventStatus;
import com.srr.service.EventService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import me.zhengjie.annotation.Log;
import me.zhengjie.utils.PageResult;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import io.swagger.annotations.*;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import me.zhengjie.utils.PageResult; import java.io.IOException;
import com.srr.dto.EventDto;
/** /**
* @website https://eladmin.vip * @author Chanheng
* @author Chanheng * @website https://eladmin.vip
* @date 2025-05-18 * @date 2025-05-18
**/ **/
@RestController @RestController
@RequiredArgsConstructor @RequiredArgsConstructor
@Api(tags = "event") @Api(tags = "event")
@ -55,26 +60,48 @@ public class EventController {
@GetMapping @GetMapping
@ApiOperation("Query event") @ApiOperation("Query event")
@PreAuthorize("@el.check('event:list')") @PreAuthorize("@el.check('event:list')")
public ResponseEntity<PageResult<EventDto>> queryEvent(EventQueryCriteria criteria, Pageable pageable){ public ResponseEntity<PageResult<EventDto>> queryEvent(EventQueryCriteria criteria, Pageable pageable) {
return new ResponseEntity<>(eventService.queryAll(criteria,pageable),HttpStatus.OK); return new ResponseEntity<>(eventService.queryAll(criteria, pageable), HttpStatus.OK);
} }
@PostMapping @PostMapping
@Log("Add event") @Log("Add event")
@ApiOperation("Add event") @ApiOperation("Add event")
@PreAuthorize("@el.check('event:add')") @PreAuthorize("@el.check('event:add')")
public ResponseEntity<Object> createEvent(@Validated @RequestBody Event resources){ public ResponseEntity<Object> createEvent(@Validated @RequestBody Event resources) {
eventService.create(resources); final var result = eventService.create(resources);
return new ResponseEntity<>(HttpStatus.CREATED); return new ResponseEntity<>(result, HttpStatus.CREATED);
} }
@PutMapping @PutMapping
@Log("Modify event") @Log("Modify event")
@ApiOperation("Modify event") @ApiOperation("Modify event")
@PreAuthorize("@el.check('event:edit')") @PreAuthorize("@el.check('event:edit')")
public ResponseEntity<Object> updateEvent(@Validated @RequestBody Event resources){ public ResponseEntity<Object> updateEvent(@Validated @RequestBody Event resources) {
eventService.update(resources); final var result = eventService.update(resources);
return new ResponseEntity<>(HttpStatus.NO_CONTENT); return new ResponseEntity<>(result, HttpStatus.OK);
}
@PatchMapping("/{id}/status/{status}")
@Log("Update event status")
@ApiOperation("Update event status")
@PreAuthorize("@el.check('event:edit')")
public ResponseEntity<Object> updateEventStatus(
@PathVariable Long id,
@PathVariable EventStatus status) {
final var result = eventService.updateStatus(id, status);
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);
} }
@DeleteMapping @DeleteMapping

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,8 @@ package com.srr.service;
import com.srr.domain.Event; import com.srr.domain.Event;
import com.srr.dto.EventDto; import com.srr.dto.EventDto;
import com.srr.dto.EventQueryCriteria; import com.srr.dto.EventQueryCriteria;
import com.srr.dto.JoinEventDto;
import com.srr.enumeration.EventStatus;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import java.util.List; import java.util.List;
@ -59,13 +61,22 @@ public interface EventService {
* Create * Create
* @param resources / * @param resources /
*/ */
void create(Event resources); EventDto create(Event resources);
/** /**
* Edit * Edit
* @param resources / * @param resources /
*/ */
void update(Event resources); EventDto update(Event resources);
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 * Multi-select delete

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

@ -1,21 +1,23 @@
/* /*
* Copyright 2019-2025 Zheng Jie * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.srr.service.impl; package com.srr.service.impl;
import com.srr.domain.Event; import com.srr.domain.Event;
import com.srr.enumeration.EventStatus;
import me.zhengjie.exception.EntityNotFoundException;
import me.zhengjie.utils.ValidationUtil; import me.zhengjie.utils.ValidationUtil;
import me.zhengjie.utils.FileUtil; import me.zhengjie.utils.FileUtil;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -24,65 +26,138 @@ import com.srr.service.EventService;
import com.srr.dto.EventDto; import com.srr.dto.EventDto;
import com.srr.dto.EventQueryCriteria; import com.srr.dto.EventQueryCriteria;
import com.srr.dto.mapstruct.EventMapper; 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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import me.zhengjie.utils.PageUtil; import me.zhengjie.utils.PageUtil;
import me.zhengjie.utils.QueryHelp; import me.zhengjie.utils.QueryHelp;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.io.IOException; import java.io.IOException;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import me.zhengjie.utils.PageResult; import me.zhengjie.utils.PageResult;
/** /**
* @website https://eladmin.vip * @author Chanheng
* @description * @website https://eladmin.vip
* @author Chanheng * @description
* @date 2025-05-18 * @date 2025-05-18
**/ **/
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class EventServiceImpl implements EventService { public class EventServiceImpl implements EventService {
private final EventRepository eventRepository; private final EventRepository eventRepository;
private final EventMapper eventMapper; private final EventMapper eventMapper;
private final TeamRepository teamRepository;
private final TeamPlayerRepository teamPlayerRepository;
@Override @Override
public PageResult<EventDto> queryAll(EventQueryCriteria criteria, Pageable pageable){ public PageResult<EventDto> queryAll(EventQueryCriteria criteria, Pageable pageable) {
Page<Event> page = eventRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); Page<Event> page = eventRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);
return PageUtil.toPage(page.map(eventMapper::toDto)); return PageUtil.toPage(page.map(eventMapper::toDto));
} }
@Override @Override
public List<EventDto> queryAll(EventQueryCriteria criteria){ public List<EventDto> queryAll(EventQueryCriteria criteria) {
return eventMapper.toDto(eventRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder))); return eventMapper.toDto(eventRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)));
} }
@Override @Override
@Transactional @Transactional
public EventDto findById(Long id) { public EventDto findById(Long id) {
Event event = eventRepository.findById(id).orElseGet(Event::new); Event event = eventRepository.findById(id).orElseGet(Event::new);
ValidationUtil.isNull(event.getId(),"Event","id",id); ValidationUtil.isNull(event.getId(), "Event", "id", id);
return eventMapper.toDto(event); return eventMapper.toDto(event);
} }
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void create(Event resources) { public EventDto create(Event resources) {
eventRepository.save(resources); resources.setStatus(EventStatus.DRAFT);
final var result = eventRepository.save(resources);
return eventMapper.toDto(result);
} }
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void update(Event resources) { public EventDto update(Event resources) {
Event event = eventRepository.findById(resources.getId()).orElseGet(Event::new); Event event = eventRepository.findById(resources.getId()).orElseGet(Event::new);
ValidationUtil.isNull( event.getId(),"Event","id",resources.getId()); ValidationUtil.isNull(event.getId(), "Event", "id", resources.getId());
event.copy(resources); event.copy(resources);
eventRepository.save(event); final var result = eventRepository.save(event);
return eventMapper.toDto(result);
}
@Override
@Transactional(rollbackFor = Exception.class)
public EventDto updateStatus(Long id, EventStatus status) {
Event event = eventRepository.findById(id)
.orElseThrow(() -> new EntityNotFoundException(Event.class, "id", id));
// Only update the status field
event.setStatus(status);
if (status == EventStatus.CHECK_IN) {
event.setCheckInAt(Timestamp.from(Instant.now()));
}
final var result = eventRepository.save(event);
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 @Override
@ -96,11 +171,10 @@ public class EventServiceImpl implements EventService {
public void download(List<EventDto> all, HttpServletResponse response) throws IOException { public void download(List<EventDto> all, HttpServletResponse response) throws IOException {
List<Map<String, Object>> list = new ArrayList<>(); List<Map<String, Object>> list = new ArrayList<>();
for (EventDto event : all) { for (EventDto event : all) {
Map<String,Object> map = new LinkedHashMap<>(); Map<String, Object> map = new LinkedHashMap<>();
map.put("名称", event.getName()); map.put("名称", event.getName());
map.put("描述", event.getDescription()); map.put("描述", event.getDescription());
map.put("SINGLE, DOUBLE", event.getFormat()); map.put("SINGLE, DOUBLE", event.getFormat());
map.put("最大人数", event.getMaxPlayer());
map.put("位置", event.getLocation()); map.put("位置", event.getLocation());
map.put("图片", event.getImage()); map.put("图片", event.getImage());
map.put("创建时间", event.getCreateTime()); map.put("创建时间", event.getCreateTime());
@ -108,8 +182,8 @@ public class EventServiceImpl implements EventService {
map.put("排序", event.getSort()); map.put("排序", event.getSort());
map.put("是否启用", event.getEnabled()); map.put("是否启用", event.getEnabled());
map.put("时间", event.getEventTime()); map.put("时间", event.getEventTime());
map.put(" clubId", event.getClubId()); map.put(" clubId", event.getClubId());
map.put(" createBy", event.getCreateBy()); map.put(" createBy", event.getCreateBy());
list.add(map); list.add(map);
} }
FileUtil.downloadExcel(list, response); FileUtil.downloadExcel(list, response);

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;
}
}