diff --git a/src/main/java/uk/ac/cf/spring/demo/sports/match/MatchController.java b/src/main/java/uk/ac/cf/spring/demo/sports/match/MatchController.java index 7187714d98bf0645345a1cc3befbd6055567acba..4f5f2783241cd95d74d31f2bd973cafe02bca75e 100644 --- a/src/main/java/uk/ac/cf/spring/demo/sports/match/MatchController.java +++ b/src/main/java/uk/ac/cf/spring/demo/sports/match/MatchController.java @@ -1,7 +1,10 @@ package uk.ac.cf.spring.demo.sports.match; +import jakarta.servlet.http.HttpSession; import org.springframework.beans.factory.annotation.Autowired; //import org.springframework.stereotype.Controller; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; //import org.springframework.web.servlet.ModelAndView; @@ -17,12 +20,12 @@ public class MatchController { } // get all Match List @GetMapping - public List<MatchItem> getAllMenuItems() { + public List<MatchItem> getAllMatchItems() { return matchService.getMatchItems(); } // get Match by id @GetMapping("/{id}") - public MatchItem getMenuItem(@PathVariable Long id) { + public MatchItem getMatchItem(@PathVariable Long id) { return matchService.getMatchItemById(id); } @@ -44,8 +47,23 @@ public class MatchController { public void deleteMatchItem(@PathVariable Long id) { matchService.deleteMatchItem(id); } - - +//fail to come true +// @PutMapping("/{id}") +// public ResponseEntity<String> updateMatchItem(@PathVariable Long id, @RequestBody MatchItem matchItem, HttpSession session) { +// Long userId = (Long) session.getAttribute("userId"); +// if (userId == null) { +// return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("{\"message\": \"User not logged in\"}"); +// } +// if(matchItem.getPlayerAId() == 0) { +// matchItem.setPlayerAId(userId); +// }else { +// matchItem.setPlayerBId(userId); +// } +// +// matchItem.setId(id); +// matchService.updateMatchItem(matchItem); +// return ResponseEntity.ok("{\"message\": \"Match added successfully\"}"); +// } // @GetMapping("/match") // public ModelAndView getMatch() { // ModelAndView modelAndView = new ModelAndView("match/allMatchList"); diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 20f0049e108b141d5cabd5e5a74c4afb4ee87063..bf9a6849befaab87faf8efb43582fe533f26be54 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -1,23 +1,40 @@ +delete from information; delete from match_item; delete from ranking; -insert into match_item (sport, player_AId, player_BId, plan_Time, status, score_a, score_b, confirm_a, confirm_b, winner_id) -values --- test data --- 1: Pending status - ('Pools', 1, 2, '2024-11-25 14:30:00', 'pending', 0, 0, FALSE, FALSE, NULL), --- 2: Confirmed status, Player 3 wins - ('Darts', 3, 4, '2024-11-26 16:00:00', 'confirmed', 3, 2, TRUE, TRUE, 3), --- 3: Completed status, Player 6 wins - ('TableTennis', 1, 2, '2024-11-27 18:00:00', 'completed', 21, 18, TRUE, TRUE, 2), --- 4: Pending status - ('Pools', 2, 1, '2024-11-28 20:00:00', 'pending', 0, 0, FALSE, FALSE, NULL), --- 5: Completed status, Player 9 wins - ('Darts', 1, 2, '2024-11-29 15:30:00', 'completed', 300, 280, TRUE, TRUE, 2), --- 6: Confirmed status, Player 1 wins - ('TableTennis', 1, 2, '2024-11-30 17:00:00', 'confirmed', 3, 1, TRUE, TRUE, 1); +INSERT INTO information (id, username, email, password, role) +VALUES (1, 'shy', 'shy@creditsafe.com', '$2a$16$R0aSGzbklUhpRfIMhocewephgUDMFOffLb7faSwwHusqHh81G026i', 'USER'); +INSERT INTO information (id, username, email, password, role) +VALUES (2, 'zyb', 'zyb@creditsafe.com', '$2a$16$R0aSGzbklUhpRfIMhocewephgUDMFOffLb7faSwwHusqHh81G026i', 'USER'); +INSERT INTO information (id, username, email, password, role) +VALUES (3, 'xzc', 'xzc@creditsafe.com', '$2a$16$R0aSGzbklUhpRfIMhocewephgUDMFOffLb7faSwwHusqHh81G026i', 'USER'); +INSERT INTO information (id, username, email, password, role) +VALUES (4, 'xx', 'xx@creditsafe.com', '$2a$16$R0aSGzbklUhpRfIMhocewephgUDMFOffLb7faSwwHusqHh81G026i', 'USER'); +# insert into match_item (sport, player_AId, player_BId, plan_Time, status, score_a, score_b, confirm_a, confirm_b, winner_id) +# values +# -- test data +# -- 1: Pending status +# ('Pools', 1, 2, '2024-11-25 14:30:00', 'pending', 0, 0, FALSE, FALSE, NULL), +# -- 2: Confirmed status, Player 3 wins +# ('Darts', 3, 4, '2024-11-26 16:00:00', 'confirmed', 3, 2, TRUE, TRUE, 3), +# -- 3: Completed status, Player 6 wins +# ('TableTennis', 1, 2, '2024-11-27 18:00:00', 'completed', 21, 18, TRUE, TRUE, 2), +# -- 4: Pending status +# ('Pools', 2, 1, '2024-11-28 20:00:00', 'pending', 0, 0, FALSE, FALSE, NULL), +# -- 5: Completed status, Player 9 wins +# ('Darts', 1, 2, '2024-11-29 15:30:00', 'completed', 300, 280, TRUE, TRUE, 2), +# -- 6: Confirmed status, Player 1 wins +# ('TableTennis', 1, 2, '2024-11-30 17:00:00', 'confirmed', 3, 1, TRUE, TRUE, 1), +# ('TableTennis', null, null, '2024-12-20 17:00:00', 'pending', 0, 0, false, false, null), +# ('TableTennis', null, null, '2024-12-21 17:00:00', 'pending', 0, 0, false, false, null), +# ('Pools', null, null, '2024-12-22 17:00:00', 'pending', 0, 0, false, false, null), +# ('Pools', null, null, '2024-12-23 17:00:00', 'pending', 0, 0, false, false, null), +# ('Pools', null, null, '2024-12-24 17:00:00', 'pending', 0, 0, false, false, null), +# ('Darts', null, null, '2024-12-25 17:00:00', 'pending', 0, 0, false, false, null), +# ('Darts', null, null, '2024-12-26 17:00:00', 'pending', 0, 0, false, false, null), +# ('Darts', null, null, '2024-12-27 17:00:00', 'pending', 0, 0, false, false, null); INSERT INTO ranking (user_id,username,sport, wins) VALUES - (1, 'xzc','Pools', 5), - (2, 'shy','Darts', 3), - (3, 'xx','TableTennis', 10), - (2, 'shy','TableTennis', 4); + (1, 'shy','Pools', 5), + (2, 'zyb','Darts', 3), + (3, 'xzc','TableTennis', 10), + (2, 'xx','TableTennis', 4); diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 79e19efcafd5f442a7381d58c0f239973ea5b207..82dc0657f8670edb6b2ff9196240444d93ac8912 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,14 +1,22 @@ drop table if exists match_item; drop table if exists rankings; +drop table if exists information; +CREATE TABLE information ( + id INT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50) UNIQUE NOT NULL, + email VARCHAR(50) UNIQUE NOT NULL, + password VARCHAR(255) NOT NULL, + role VARCHAR(20) DEFAULT 'USER' NOT NULL +); create table if not exists match_item ( -- Match ID id BIGINT AUTO_INCREMENT PRIMARY KEY, -- Sport type sport ENUM('Pools', 'Darts', 'TableTennis') NOT NULL, -- Player A ID - player_AId BIGINT NOT NULL, + player_AId INT NULL, -- Player B ID - player_BId BIGINT NOT NULL, + player_BId INT NULL, plan_Time DATETIME NOT NULL, -- Match status status ENUM('pending', 'confirmed', 'completed') DEFAULT 'pending', @@ -16,16 +24,14 @@ create table if not exists match_item ( score_b INT DEFAULT 0, confirm_a BOOLEAN DEFAULT FALSE, confirm_b BOOLEAN DEFAULT FALSE, - winner_id BIGINT DEFAULT NULL + winner_id BIGINT DEFAULT NULL, +# FOREIGN KEY (player_AId) REFERENCES information(id) ON DELETE CASCADE, +# FOREIGN KEY (player_BId) REFERENCES information(id) ON DELETE CASCADE + FOREIGN KEY (player_AId) REFERENCES information(id) ON DELETE SET NULL, + FOREIGN KEY (player_BId) REFERENCES information(id) ON DELETE SET NULL ); -drop table if exists information; -CREATE TABLE information ( - id INT AUTO_INCREMENT PRIMARY KEY, - username VARCHAR(50) UNIQUE NOT NULL, - email VARCHAR(50) UNIQUE NOT NULL, - password VARCHAR(255) NOT NULL, - role VARCHAR(20) DEFAULT 'USER' NOT NULL -); + + drop table if exists ranking; CREATE TABLE IF NOT EXISTS ranking ( id INT AUTO_INCREMENT PRIMARY KEY, diff --git a/src/main/resources/static/css/backendMatch.css b/src/main/resources/static/css/backendMatch.css new file mode 100644 index 0000000000000000000000000000000000000000..0648de307aff5e67caee041f7aac613e55964224 --- /dev/null +++ b/src/main/resources/static/css/backendMatch.css @@ -0,0 +1,106 @@ +body { + font-family: Arial, Helvetica, sans-serif; + margin: 0; + padding: 0; + background: linear-gradient(to right, #e0f7fa, #ffffff); + color: #333; +} +h1, h2 { + text-align: center; + color: #0277bd; +} +.generateBtn { + display: flex; + justify-content: center; + align-items: center; + +} +button { + background-color: #0288d1; + color: white; + border: none; + padding: 10px 20px; + margin: 10px auto; + font-size: 16px; + border-radius: 5px; + cursor: pointer; + transition: background-color 0.3s ease; + +} + +button:hover { + background-color: #0277bd; +} + +table { + width: 90%; + margin: 20px auto; + border-collapse: collapse; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); +} + +th, td { + border: 1px solid #ddd; + padding: 8px; + text-align: center; +} + +thead { + background-color: #0288d1; + color: white; +} + +tr:nth-child(even) { + background-color: #f1f1f1; +} + +tr:hover { + background-color: #d1eafc; +} + +/* è¡¨å•æ ·å¼ */ +#addMatchForm { + width: 80%; + margin: 20px auto; + padding: 20px; + border: 1px solid #ddd; + border-radius: 8px; + background: #f8f9fa; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); +} + +form { + display: flex; + flex-wrap: wrap; + gap: 10px; +} + +form label { + flex: 1 1 100px; + font-weight: bold; + color: #555; +} + +form input[type="text"], +form input[type="number"], +form input[type="datetime-local"] { + flex: 2 1 200px; + padding: 5px; + border: 1px solid #aaa; + border-radius: 4px; +} + +form button { + flex: 1 1 100px; + margin-top: 10px; +} + +@media screen and (max-width: 768px) { + #addMatchForm form { + flex-direction: column; + } + + form label, form input { + width: 100%; + } +} \ No newline at end of file diff --git a/src/main/resources/static/css/matchDetailChangeScore.css b/src/main/resources/static/css/matchDetailChangeScore.css index 8fafb117de2001eed4b70313002dc35d3d1be398..5ed8471cc5876afdcdec65909e76fa3c34f89643 100644 --- a/src/main/resources/static/css/matchDetailChangeScore.css +++ b/src/main/resources/static/css/matchDetailChangeScore.css @@ -78,11 +78,32 @@ h2 { #sport, #playerAId, #playerBId, -#status, #confirmByA, #confirmByB { display: none; } +input[type="number"], +input[type="text"], +input[type="datetime-local"], +select { + width: 100%; + padding: 8px; + margin-bottom: 10px; + border: 1px solid #555; + border-radius: 4px; + outline: none; + transition: border-color 0.2s ease; +} +input[type="number"]:focus, +input[type="text"]:focus, +input[type="datetime-local"]:focus, +select:focus { + border-color: #333; +} +select { + background-color: #fff; + color: #333; +} button { margin: 10px; padding: 10px 20px; diff --git a/src/main/resources/static/html/backGroundMatch.html b/src/main/resources/static/html/backGroundMatch.html index 68434033b4d832d1f3feaa880a7a436630a0def4..76e46e2229cdba38b0ec8b3c1bbd25ee18a31426 100644 --- a/src/main/resources/static/html/backGroundMatch.html +++ b/src/main/resources/static/html/backGroundMatch.html @@ -4,11 +4,18 @@ <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Match Management</title> - <link rel="stylesheet" href="/css/backGroundMatch.css"> +<!-- <link rel="stylesheet" href="/css/backGroundMatch.css">--> + <link rel="stylesheet" href="/css/backendMatch.css"> </head> <body> <h1>Match Management</h1> <h2>Match List</h2> + <div class="generateBtn"> + <button id="generatePoolsMatches">generate Pools</button> + <button id="generateDartsMatches">generate Darts</button> + <button id="generateTableTennisMatches">generate TableTennis</button> + </div> + <table id="matchTable"> <thead> <tr> diff --git a/src/main/resources/static/html/matchDetailChangeScore.html b/src/main/resources/static/html/matchDetailChangeScore.html index ada5b7a395967a9dbb5ff985e8684bfcf3fd7c7e..00af7284435561922d8e608d2df39b4d709098f4 100644 --- a/src/main/resources/static/html/matchDetailChangeScore.html +++ b/src/main/resources/static/html/matchDetailChangeScore.html @@ -35,7 +35,13 @@ <label for="planTime">Plan Time: </label> <input type="datetime-local" id="planTime" name="planTime" required><br> <!-- <label for="status">Status: </label>--> - <input type="text" id="status" name="status" required><br> +<!-- <input type="text" id="status" name="status" required><br>--> + <label for="status">Status: </label> + <select id="status" name="status" required> + <option value="pending">Pending</option> + <option value="confirmed">Confirmed</option> + <option value="completed">Completed</option> + </select><br> <!-- <label for="confirmByA">Confirm by A: </label>--> <input type="checkbox" id="confirmByA" name="confirmByA"><br> <!-- <label for="confirmByB">Confirm by B: </label>--> diff --git a/src/main/resources/static/html/matchSchedule.html b/src/main/resources/static/html/matchSchedule.html index 884a117f7dbd436c7aa1778c3730cb8e66e65d44..3918cc6c3ba489483556ac59c2916cf20ec6df31 100644 --- a/src/main/resources/static/html/matchSchedule.html +++ b/src/main/resources/static/html/matchSchedule.html @@ -6,6 +6,13 @@ <link rel="stylesheet" type="text/css" href="/css/navBar.css"> <link rel="stylesheet" href="/css/footer.css"> <link rel="stylesheet" href="/css/matchSchedule.css"> + <style> + .generateBtn{ + display: flex; + justify-content: space-around; + margin-bottom: 10px; + } + </style> </head> <body> @@ -17,6 +24,12 @@ <div class="container"> <!-- <h1>Sports League Schedule</h1>--> + <div class="generateBtn"> + <button id="generatePoolsMatches">generate Pools</button> + <button id="generateDartsMatches">generate Darts</button> + <button id="generateTableTennisMatches">generate TableTennis</button> + </div> + <!-- Filter --> <div class="filter-panel"> <label for="sportSelect">Filter by Sport:</label> diff --git a/src/main/resources/static/js/backGroundMatch.js b/src/main/resources/static/js/backGroundMatch.js index 7e5948c1a690fe7768d9b7c2957869dcdd0a61fb..330e4cdc6c1cf910ece0564adcb4161efcc41d91 100644 --- a/src/main/resources/static/js/backGroundMatch.js +++ b/src/main/resources/static/js/backGroundMatch.js @@ -1,5 +1,6 @@ const MATCHES_API_URL = '/match'; // let matches = [] +const playerIds = [1, 2, 3, 4]; window.onload = function() { fetchMatchItems(); }; @@ -47,7 +48,106 @@ window.onload = function() { // tableBody.appendChild(row); // }); // } - +function generatePoolsCombinations() { + const matches = []; + let currentPlanTime = new Date(); + for (let i = 0; i < playerIds.length; i++) { + for (let j = i + 1; j < playerIds.length; j++) { + matches.push({ + sport: "Pools", + playerAId: playerIds[i], + playerBId: playerIds[j], + planTime: currentPlanTime.toISOString(), + status: "pending", + score_a: 0, + score_b: 0, + confirm_a: false, + confirm_b: false, + winner_id: null, + }); + currentPlanTime.setDate(currentPlanTime.getDate() + 1); + } + } + return matches; +} +function generateDartsCombinations() { + const matches = []; + let currentPlanTime = new Date(); + for (let i = 0; i < playerIds.length; i++) { + for (let j = i + 1; j < playerIds.length; j++) { + matches.push({ + sport: "Darts", + playerAId: playerIds[i], + playerBId: playerIds[j], + planTime: currentPlanTime.toISOString(), + status: "pending", + score_a: 0, + score_b: 0, + confirm_a: false, + confirm_b: false, + winner_id: null, + }); + currentPlanTime.setDate(currentPlanTime.getDate() + 1); + } + } + return matches; +} +function generateTableTennisCombinations() { + const matches = []; + let currentPlanTime = new Date(); + for (let i = 0; i < playerIds.length; i++) { + for (let j = i + 1; j < playerIds.length; j++) { + matches.push({ + sport: "TableTennis", + playerAId: playerIds[i], + playerBId: playerIds[j], + planTime: currentPlanTime.toISOString(), + status: "pending", + score_a: 0, + score_b: 0, + confirm_a: false, + confirm_b: false, + winner_id: null, + }); + currentPlanTime.setDate(currentPlanTime.getDate() + 1); + } + } + return matches; +} +async function submitMatchesToServer(matches) { + for (const match of matches) { + try { + const res = await fetch(MATCHES_API_URL, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(match), + }); + if (!res.ok) { + throw new Error(`${match.playerAId} vs ${match.playerBId}`); + } + console.log(`error2:${match.playerAId} vs ${match.playerBId}`); + } catch (error) { + console.error("error1", error); + } + } +} +document.getElementById("generatePoolsMatches").addEventListener("click", async () => { + const matches = generatePoolsCombinations(); + console.log("generate list", matches); + await submitMatchesToServer(matches); +}); +document.getElementById("generateDartsMatches").addEventListener("click", async () => { + const matches = generateDartsCombinations(); + console.log("generate list", matches); + await submitMatchesToServer(matches); +}); +document.getElementById("generateTableTennisMatches").addEventListener("click", async () => { + const matches = generateTableTennisCombinations(); + console.log("generate list", matches); + await submitMatchesToServer(matches); +}); // show all matches function fetchMatchItems() { fetch(MATCHES_API_URL) diff --git a/src/main/resources/static/js/matchSchedule.js b/src/main/resources/static/js/matchSchedule.js index 2b1f0e5f201622ea094718a482a9e246989c0537..e3b6a5b58d609d7c2f3c1a4defef7af8ecca0f27 100644 --- a/src/main/resources/static/js/matchSchedule.js +++ b/src/main/resources/static/js/matchSchedule.js @@ -1,6 +1,107 @@ const MATCHES_API_URL = '/match'; // fixed bug let matches = []; +const playerIds = [1, 2, 3, 4]; +function generatePoolsCombinations() { + const matches = []; + let currentPlanTime = new Date(); + for (let i = 0; i < playerIds.length; i++) { + for (let j = i + 1; j < playerIds.length; j++) { + matches.push({ + sport: "Pools", + playerAId: playerIds[i], + playerBId: playerIds[j], + planTime: currentPlanTime.toISOString(), + status: "pending", + score_a: 0, + score_b: 0, + confirm_a: false, + confirm_b: false, + winner_id: null, + }); + currentPlanTime.setDate(currentPlanTime.getDate() + 1); + } + } + return matches; +} +function generateDartsCombinations() { + const matches = []; + let currentPlanTime = new Date(); + for (let i = 0; i < playerIds.length; i++) { + for (let j = i + 1; j < playerIds.length; j++) { + matches.push({ + sport: "Darts", + playerAId: playerIds[i], + playerBId: playerIds[j], + planTime: currentPlanTime.toISOString(), + status: "pending", + score_a: 0, + score_b: 0, + confirm_a: false, + confirm_b: false, + winner_id: null, + }); + currentPlanTime.setDate(currentPlanTime.getDate() + 1); + } + } + return matches; +} +function generateTableTennisCombinations() { + const matches = []; + let currentPlanTime = new Date(); + for (let i = 0; i < playerIds.length; i++) { + for (let j = i + 1; j < playerIds.length; j++) { + matches.push({ + sport: "TableTennis", + playerAId: playerIds[i], + playerBId: playerIds[j], + planTime: currentPlanTime.toISOString(), + status: "pending", + score_a: 0, + score_b: 0, + confirm_a: false, + confirm_b: false, + winner_id: null, + }); + currentPlanTime.setDate(currentPlanTime.getDate() + 1); + } + } + return matches; +} +async function submitMatchesToServer(matches) { + for (const match of matches) { + try { + const res = await fetch(MATCHES_API_URL, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(match), + }); + if (!res.ok) { + throw new Error(`${match.playerAId} vs ${match.playerBId}`); + } + console.log(`error2:${match.playerAId} vs ${match.playerBId}`); + } catch (error) { + console.error("error1", error); + } + } +} +document.getElementById("generatePoolsMatches").addEventListener("click", async () => { + const matches = generatePoolsCombinations(); + console.log("generate list", matches); + await submitMatchesToServer(matches); +}); +document.getElementById("generateDartsMatches").addEventListener("click", async () => { + const matches = generateDartsCombinations(); + console.log("generate list", matches); + await submitMatchesToServer(matches); +}); +document.getElementById("generateTableTennisMatches").addEventListener("click", async () => { + const matches = generateTableTennisCombinations(); + console.log("generate list", matches); + await submitMatchesToServer(matches); +}); // 页é¢åŠ è½½æ—¶è‡ªåŠ¨èŽ·å–并展示所有比赛 // show all the matches async function fetchMatches() {