<template> <div class="background"> <img v-if="pre_background_image" :src="pre_background_image" class="img1" alt="上传背景图"> <div v-if="!pre_background_image">点击头像处上传背景图</div> <!-- <v-overlay activator="parent" /> --> </div> <!-- <v-overlay activator=".img1" /> --> <!-- <v-container class="relative"> --> <div class="yuanjiao"> <div class="d-flex justify-start align-stretch relative "> <!-- 头像 --> <v-menu rounded> <template v-slot:activator="{ props }"> <v-btn icon v-bind="props" class="float-left" size="80px"> <v-avatar size="80px" style="border:3px solid white"> <img v-if="pre_avatar_image" :src="pre_avatar_image" class="img2" alt="上传头像"> <div v-if="!pre_avatar_image" class="alt-text">上传头像</div> </v-avatar> </v-btn> </template> <v-card v-if="players_id === 0"> <v-card-text> <div class="mx-auto text-center"> <v-avatar size="50px"> <img v-if="pre_avatar_image" :src="pre_avatar_image" class="img2" alt="上传头像"> <div v-if="!pre_avatar_image" class="alt-text">上传头像</div> </v-avatar> <div class="text-h5 relative1"> {{ username }} </div> <v-divider class="my-2"></v-divider> <v-btn @click="dialog1 = true" variant="text" rounded class="jiacu"> 上传头像 </v-btn> <v-divider class="my-2"></v-divider> <v-btn @click="dialog2 = true" variant="text" rounded class="jiacu"> 上传背景 </v-btn> <v-divider class="my-2"></v-divider> <v-btn @click="dialog3 = true" variant="text" rounded class="jiacu"> 修改个人信息 </v-btn> </div> </v-card-text> </v-card> </v-menu> <div class="flex-1-0"> <div class="d-flex justify-start align-center user-info-box"> <div class="text-h6 user"> {{ username }} </div> <!-- <div class="text-subtitle-1 user float-left" style="color:red;"> {{ level }}级 </div> --> <div class="text-subtitle-1 user"> {{ group }}组 </div> <div class="text-subtitle-1 user"> {{ total_game }}场 </div> </div> <div class="d-flex justify-start align-center"> <div class="text-subtitle-1 user1"> 积分:{{ score }} </div> <div class="text-subtitle-1 user1"> 胜率:{{ winrate }}% </div> </div> </div> </div> <div class="game-relative" v-if="exist_season"> <v-card class="game-card" elevation="5"> <template v-slot:prepend> <v-icon size="25px">mdi-trophy</v-icon> </template> <template v-slot:title> <div class="text-h6">最近比赛</div> </template> <v-list> <v-list-item v-for="(item, index) in items" :key="index" :value="item" @click="myGameDeail(item.id)"> <template v-slot:default> <div class="d-flex justify-space-between align-center game-card-item"> <div> <v-avatar size="48px"><img :src="item.homeTeam_avatar" class="img2"></v-avatar> </div> <div class="game-name-score"> <div class="game-score-text">{{ item.homeScore }}</div> <div class="game-name-text">{{ item.homeTeam }}</div> </div> <div> : </div> <div class="game-name-score"> <div class="game-score-text">{{ item.awayScore }}</div> <div class="game-name-text">{{ item.awayTeam }}</div> </div> <div> <v-avatar size="48px"><img :src="item.awayTeam_avatar" class="img2"></v-avatar> </div> <div> <!-- <div>{{ item.year }}</div> --> <div class="game-date-text">{{ item.date }}</div> </div> <v-icon>mdi-chevron-right</v-icon> </div> </template> </v-list-item> </v-list> <v-divider></v-divider> <v-card-actions> <v-spacer></v-spacer> <v-btn color="indigo" variant="text" @click="button1" text="更多"></v-btn> </v-card-actions> </v-card> </div> </div> <v-dialog v-model="dialog1" width="auto"> <v-card width="300px"> <v-card-text> 头像上传 </v-card-text> <v-card-text> <v-file-input show-size accept="image/*" id="avatarInput" label="上传头像" prepend-icon="mdi-camera" variant="solo"></v-file-input> </v-card-text> <v-card-actions> <v-spacer></v-spacer> <v-btn color="indigo" text="取消" @click="dialog1 = false"></v-btn> <v-btn color="indigo" text="上传" :loading="avatarLoading" @click="setAvatar"></v-btn> </v-card-actions> </v-card> </v-dialog> <v-dialog v-model="dialog2" width="auto"> <v-card width="300px"> <v-card-text> 背景上传 </v-card-text> <v-card-text> <v-file-input accept="image/*" id="backgroundInput" label="上传背景" prepend-icon="mdi-camera" variant="solo"></v-file-input> </v-card-text> <v-card-actions> <v-spacer></v-spacer> <v-btn color="indigo" text="取消" @click="dialog2 = false"></v-btn> <v-btn color="indigo" text="上传" :loading="backgroundLoading" @click="setBackground"></v-btn> </v-card-actions> </v-card> </v-dialog> <v-dialog v-model="dialog3" width="auto"> <v-card width="300px"> <v-form ref="form"> <v-card-text> 修改个人信息 </v-card-text> <v-card-text> <v-text-field v-model="username1" variant="filled" color="indigo" label="修改用户名"></v-text-field> <v-text-field v-model="password" variant="filled" color="indigo" label="修改密码" type="password"></v-text-field> <v-text-field v-model="confirmpassword" variant="filled" :rules="[rules.confirmpassword]" color="indigo" label="确认密码" type="password"></v-text-field> </v-card-text> </v-form> <v-card-actions> <v-spacer></v-spacer> <v-btn color="indigo" text="取消" @click="dialog3 = false"></v-btn> <v-btn color="indigo" text="修改" :loading="informLoading" @click="setUserinform"></v-btn> </v-card-actions> </v-card> </v-dialog> <v-dialog v-model="dialog" width="auto"> <v-card width="300px"> <v-card-title> {{ cardtitle }} </v-card-title> <v-card-text> {{ cardtext }} </v-card-text> <template v-slot:actions> <v-btn class="ms-auto" variant="flat" color="indigo" text="确认" @click="dialog = false"></v-btn> </template> </v-card> </v-dialog> <v-dialog v-model="mygame_dialog" width="auto"> <v-card width="300px"> <template v-slot:prepend> <v-icon size="25px">mdi-trophy</v-icon> </template> <template v-slot:title> <div class="text-h6">比赛详情</div> </template> <template v-slot:subtitle> <div>{{ mygame_detail.game_date }}</div> </template> <template v-slot:default> <div class="d-flex justify-space-between align-center gameDetail-item"> <div> <v-avatar size="48px"><img :src="mygame_detail.player1_profile_file" class="img2"></v-avatar> </div> <div class="game-name-score"> <div class="game-score-text">{{ mygame_detail.score1 }}</div> <div class="game-name-text">{{ mygame_detail.player1_real_name }}</div> </div> <div> : </div> <div class="game-name-score"> <div class="game-score-text">{{ mygame_detail.score2 }}</div> <div class="game-name-text">{{ mygame_detail.player2_real_name }}</div> </div> <div> <v-avatar size="48px"><img :src="mygame_detail.player2_profile_file" class="img2"></v-avatar> </div> </div> <div class="d-flex justify-space-between align-center gameDetail-item"> <div class="game-name-score"> <div class="text-h6">发起:</div> </div> <div>{{ mygame_detail.laucher_real_name }}</div> <div class="game-name-text">{{ mygame_detail.lauch_date }}</div> </div> <div class="d-flex justify-space-between align-center gameDetail-item"> <div class="game-name-score"> <div class="text-h6">审核:</div> </div> <div>{{ mygame_detail.confirmer_real_name }}</div> <div class="game-name-text">{{ mygame_detail.confirm_date }}</div> </div> </template> <template v-slot:actions> <v-btn class="ms-auto" variant="text" color="indigo" text="确定" @click="mygame_dialog = false"></v-btn> </template> </v-card> </v-dialog> </template> <script setup> import { ref, watch } from 'vue'; import { reactive } from 'vue'; import axios from 'axios'; import CryptoJS from 'crypto-js'; const form = ref(null); const password = ref(null); const confirmpassword = ref(null); const username = ref('XXX'); const username1 = ref(null); const score = ref(0); const group = ref(null); //const level = ref("A"); const items = ref(new Array()); const dialog = ref(false); const dialog1 = ref(false); const dialog2 = ref(false); const dialog3 = ref(false); const pre_avatar_image = ref(''); const pre_background_image = ref(''); var my_id = 0; const total_game = ref(0); const winrate = ref(null); const cardtitle = ref(null); const cardtext = ref(null); const rules = reactive({ email: v => !!(v || '').match(/@/) || 'Please enter a valid email', length: len => v => (v || '').length >= len || `Invalid character length, required ${len}`, usrname: v => !!v || '用户名不能为空', password: v => !!v || '密码不能为空', // password: v => !!(v || '').match(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*(_|[^\w])).+$/) || // 'Password must contain an upper case letter, a numeric character, and a special character', required: v => !!v || 'This field is required', username: v => !!v || '姓名不能为空', confirmpassword: v => v === password.value || '密码不匹配', }); const mygame_detail = ref({ game_date: "", player1_real_name: "", player1_profile_file: "", score1: 0, player2_real_name: "", player2_profile_file: "", score2: 0, laucher_real_name: "", laucher_profile_file: "", lauch_date: "", confirmer_real_name: "", confirmer_profile_file: "", confirm_date: "", game_type: 0, }); const mygame_dialog = ref(false); const exist_season = ref(false); const avatarLoading = ref(false); const backgroundLoading = ref(false); const informLoading = ref(false); var my_idstr = window.location.search; var players_id = 0; if (my_idstr) { players_id = extractNumbers(my_idstr)[0]; } function extractNumbers(str) { const pattern = /\d+/g; const matches = str.match(pattern); return matches ? matches.map(Number) : []; } function formatDate(date) { var d = new Date(date), month = '0' + (d.getMonth() + 1), day = '' + d.getDate(); // year = d.getFullYear(); return [month + '/' + day].join(''); // 返回形如 MM/DD 的字符串 } function refresh() { axios.get('/api/currentUser',) .then(function (response) { const data1 = response.data; if (data1.status === "SUCCESS") { my_id = data1.user_id; if (players_id === my_id || players_id === 0) { username.value = data1.username; pre_avatar_image.value = data1.profile_file; pre_background_image.value = data1.background_file; axios.get('/api/players', { params: { player_id: my_id } }) .then(function (response) { const data4 = response.data; exist_season.value = data4.ExistSeason; if (data4.status === "SUCCESS") { total_game.value = data4.Players[0].total_games; score.value = data4.Players[0].score; group.value = data4.Players[0].group; winrate.value = data4.Players[0].winrate; if (group.value == 1) { group.value = 'A'; } else if (group.value == 2) { group.value = 'B'; } else if (group.value == 3) { group.value = 'C'; } } }) .catch(function (error) { console.log(error); }) axios.get('/api/games', { params: { myid: my_id, } }) .then(function (response) { const data2 = response.data; var length1 = 5; if (length1 > data2.Games.length) { length1 = data2.Games.length } items.value.length = 0; for (var i = 0; i < length1; i++) { var item = { id: data2.Games[i].id, date: formatDate(data2.Games[i].game_date), homeTeam: data2.Games[i].player1_real_name, awayTeam: data2.Games[i].player2_real_name, homeScore: data2.Games[i].score1, awayScore: data2.Games[i].score2, homeTeam_avatar: data2.Games[i].player1_profile_file, awayTeam_avatar: data2.Games[i].player2_profile_file, } items.value[i] = item; } }) .catch(function (error) { console.log(error); }) } else if (players_id !== my_id) { axios.get('/api/players', { params: { player_id: players_id } }) .then(function (response) { const data4 = response.data; exist_season.value = data4.ExistSeason; if (data4.status === "SUCCESS") { total_game.value = data4.Players[0].total_games; username.value = data4.Players[0].player_real_name; pre_avatar_image.value = data4.Players[0].player_profile_file; pre_background_image.value = data4.Players[0].player_background_file; score.value = data4.Players[0].score; group.value = data4.Players[0].group; winrate.value = data4.Players[0].winrate; if (group.value == 1) { group.value = 'A'; } else if (group.value == 2) { group.value = 'B'; } else if (group.value == 3) { group.value = 'C'; } } }) .catch(function (error) { console.log(error); }) axios.get('/api/games', { params: { myid: players_id, } }) .then(function (response) { const data2 = response.data; var length1 = 5; if (length1 > data2.Games.length) { length1 = data2.Games.length } items.value.length = 0; for (var i = 0; i < length1; i++) { var item = { id: data2.Games[i].id, date: formatDate(data2.Games[i].game_date), homeTeam: data2.Games[i].player1_real_name, awayTeam: data2.Games[i].player2_real_name, homeScore: data2.Games[i].score1, awayScore: data2.Games[i].score2, homeTeam_avatar: data2.Games[i].player1_profile_file, awayTeam_avatar: data2.Games[i].player2_profile_file, } items.value[i] = item; } }) .catch(function (error) { console.log(error); }) } } }) .catch(function (error) { console.log(error); }) } refresh(); const clickMy_model = defineModel(); watch(clickMy_model, (newVal, oldVal) => { if (newVal !== oldVal) { refresh(); } }); function button1() { if (players_id !== 0) { window.location.href = '/my_recentgames.html?myid=' + players_id; } else { window.location.href = '/my_recentgames.html?myid=' + my_id; } } function info(title, text) { cardtitle.value = title; cardtext.value = text; dialog.value = true; } function md5Hash(password) { return CryptoJS.MD5(password).toString(); } function setUserinform() { informLoading.value = true; var user = { user_name: username1.value, user_password: password.value }; user.user_password = md5Hash(user.user_password); if (user.user_name !== null || user.user_password !== null) { axios.post('/api/setUserinform', user ) .then(function (response) { const data = response.data; if (data.status == 'SUCCESS') { info('修改成功!', ""); // username.value = user.user_name; } else if (data.status == 'FAILED') { info('用户名已存在!', ""); } refresh(); }) .catch(function (error) { console.log(error); }); } username1.value = null; password.value = null; confirmpassword.value = null; informLoading.value = false; } function setAvatar() { avatarLoading.value = true; const fileInput = document.querySelector('#avatarInput'); const file = fileInput.files[0]; // 使用FormData对象上传文件 const formData = new FormData(); formData.append('avatar', file); axios.post('/api/setAvatar', formData, { headers: { 'Content-Type': 'multipart/form-data' } }).then(response => { info("上传成功", ""); refresh(); console.log('上传成功', response.data); pre_avatar_image.value = response.data.new_avatar_path; }).catch(error => { info("头像需小于10MB", ""); console.error('上传失败', error); }); avatarLoading.value = false; dialog1.value = false; } function setBackground() { backgroundLoading.value = true; const background_fileInput = document.querySelector('#backgroundInput'); const background_file = background_fileInput.files[0]; // 使用FormData对象上传文件 const background_formData = new FormData(); background_formData.append('background', background_file); axios.post('/api/setBackground', background_formData, { headers: { 'Content-Type': 'multipart/form-data' } }).then(response => { console.log('上传成功', response.data); pre_background_image.value = response.data.new_background_path; }).catch(error => { info("背景需小于10MB", ""); console.error('上传失败', error); }); backgroundLoading.value = false; dialog2.value = false; refresh(); } function myGameDeail(my_gameid) { axios.get('/api/gameDetail', { params: { game_id: my_gameid, } }) .then(function (response) { const data6 = response.data; if (data6.status === "SUCCESS") { mygame_detail.value.game_date = data6.game_date; mygame_detail.value.confirmer_profile_file = data6.confirmer_profile_file; mygame_detail.value.confirmer_real_name = data6.confirmer_real_name; mygame_detail.value.laucher_profile_file = data6.laucher_profile_file; mygame_detail.value.laucher_real_name = data6.laucher_real_name; mygame_detail.value.player1_profile_file = data6.player1_profile_file; mygame_detail.value.player1_real_name = data6.player1_real_name; mygame_detail.value.player2_profile_file = data6.player2_profile_file; mygame_detail.value.player2_real_name = data6.player2_real_name; mygame_detail.value.score1 = data6.score1; mygame_detail.value.score2 = data6.score2; mygame_detail.value.game_type = data6.game_type; mygame_detail.value.confirm_date = data6.confirm_date; mygame_detail.value.lauch_date = data6.lauch_date; } }) .then(mygame_dialog.value = true) .catch(function (error) { console.log(error); }) } </script> <style> .background { width: 100%; height: 100px; position: relative; z-index: 1; } .img1 { object-fit: cover; width: 100%; height: 100%; z-index: 1; } .yuanjiao { height: 100%; border-radius: 6px; position: relative; top: -6px; z-index: 10; background-color: #F9F9F9; } .img2 { object-fit: cover; width: 100%; height: 100%; } .game-relative { position: relative; top: -22px; width: 95%; margin: auto; margin-top: 10px; } .relative { position: relative; top: -22px; height: 80px; margin-left: 20px; z-index: 10; } .user { position: relative; height: 32px; margin-left: 20px; line-height: 32px; font-family: "Times New Roman", "宋体"; } .user-info-box { margin-top: 22px; } .user1 { position: relative; margin-left: 20px; line-height: 22px; font-family: "Times New Roman", "宋体"; } .jiacu { font-weight: bold; } .relative1 { position: relative; top: 5px; } .relative2 { position: relative; top: -22px; margin-left: 20px; margin-top: 10px; margin-right: 20px; } .game-card { margin-top: 4px; } .game-card-item { height: 70px; width: 100%; /* padding: 20px; */ } .game-name-score { width: 20%; text-align: center; margin-left: 5px; margin-right: 5px; /* line-height: 33px; */ } .game-score-text { font-size: large; font-weight: bold; } .game-name-text { font-size: small; color: grey; text-align: center; } .gameDetail-item { height: 70px; width: 100%; padding-left: 20px; padding-right: 20px; } .game-date-text { width: 60px; font-size: small; color: grey; text-align: center; padding-left: 7px; padding-right: 7px; } .zhibiao1 { text-align: center; } .zhibiao2 { width: 10%; text-align: center; } .alt-text { top: 50%; left: 50%; } </style>