Commit c0ea6e29 authored by sunxiwei's avatar sunxiwei

第一版

parent b491f20b
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>比赛管理</title>
<style>
html,body,#app{
height: 100%;
}
</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="src/game_manage.js"></script>
</body>
</html>
......@@ -14,7 +14,7 @@
</head>
<body>
<div id="app"></div>
<div id="app" style="background-color: #F9F9F9;"></div>
<script type="module" src="src/home.js"></script>
</body>
......
......@@ -14,7 +14,7 @@
</head>
<body>
<div id="app"></div>
<div id="app" style="background-color: #F9F9F9;"></div>
<script type="module" src="src/main.js"></script>
</body>
......
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>南高乒乓球俱乐部</title>
<style>
html,body,#app{
height: 100%;
}
</style>
</head>
<body>
<div id="app" style="background-color: #F9F9F9;"></div>
<script type="module" src="src/manage.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>比赛列表</title>
<style>
html,body,#app{
height: 100%;
}
</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="src/my_recentgames.js"></script>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>过往赛季</title>
<style>
html,body,#app{
height: 100%;
}
</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="src/past_seasons.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>球员审核</title>
<style>
html,body,#app{
height: 100%;
}
</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="src/player_audit.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>球员管理</title>
<style>
html,body,#app{
height: 100%;
}
</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="src/player_manage.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>积分榜单</title>
<style>
html,body,#app{
height: 100%;
}
</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="src/score_ranking.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>赛季管理</title>
<style>
html,body,#app{
height: 100%;
}
</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="src/season_manage.js"></script>
</body>
</html>
......@@ -2,8 +2,8 @@
<v-app>
<!-- {{ filteredMatches }} -->
<v-container>
<v-data-table class="overflow-auto " :headers="headers" :items="filteredMatches" item-key="id"
:search="search.value" :items-per-page="10">
<v-data-table :loading="loading" class="overflow-auto " :headers="headers" :items="filteredMatches" item-key="id"
:search="search" :items-per-page="10">
<template v-slot:top>
<v-toolbar flat>
<v-toolbar-title>比赛</v-toolbar-title>
......@@ -24,11 +24,11 @@
</template>
<template v-slot:item.actions="{ item }">
<div style="width:45px"> <v-icon v-if="!item.shenhe" small color="green" @click="opendialog(item, 'approve')"
<div style="width:45px"> <v-icon small color="green" @click="opendialog(item, 'approve')"
style="padding-right: 20px;">mdi-check</v-icon>
<v-icon v-if="!item.shenhe" small color="red" @click="opendialog(item, 'reject')"
<v-icon small color="red" @click="opendialog(item, 'reject')"
style="padding-left: 20px;">mdi-close</v-icon>
<div v-if="item.shenhe" variant="text">已审核</div>
<!-- <div v-if="item.shenhe" variant="text">已审核</div> -->
</div>
</template>
......@@ -44,7 +44,7 @@
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="indigo" text="取消" @click="dialog = false"></v-btn>
<v-btn color="indigo" text="确定" @click="confirmAction"></v-btn>
<v-btn color="indigo" :loading="confirmLoading" text="确定" @click="confirmAction"></v-btn>
</v-card-actions>
</v-card>
</v-dialog>
......@@ -70,6 +70,8 @@ const shenhetitle = ref(null);
const shenhetext = ref(null);
const dialog = ref(false);
const verify = ref(true);
const loading = ref(false);
const confirmLoading = ref(false);
function info(title, text) {
cardtitle.value = title;
......@@ -78,9 +80,11 @@ function info(title, text) {
}
function refresh() {
loading.value = true;
axios.get('/api/lauchedGames',)
.then(function (response) {
const data = response.data;
matches.value.length = 0;
for (var i = 0; i < data.Games.length; i++) {
var match = {
id: data.Games[i].id,
......@@ -89,7 +93,7 @@ function refresh() {
awayTeam: data.Games[i].player2_real_name,
homeScore: data.Games[i].score1,
awayScore: data.Games[i].score2,
shenhe: false,
// shenhe: false,
}
matches.value[i] = match;
}
......@@ -97,6 +101,7 @@ function refresh() {
.catch(function (error) {
console.log(error);
})
loading.value = false;
}
refresh();
......@@ -133,9 +138,10 @@ function opendialog(game, type) {
}
function confirmAction() {
confirmLoading.value = true;
if (actiontype.value === 'approve') {
verify.value = true;
selectedMatch.value.shenhe = true;
// selectedMatch.value.shenhe = true;
axios.post('/api/confirmGame', {
game_id: selectedMatch.value.id,
confirm: verify.value,
......@@ -145,6 +151,7 @@ function confirmAction() {
if (data.status === "SUCCESS") {
console.log('success');
}
refresh();
})
.catch(function (error) {
console.log(error);
......@@ -152,7 +159,7 @@ function confirmAction() {
}
else if (actiontype.value === 'reject') {
verify.value = false;
selectedMatch.value.shenhe = true;
// selectedMatch.value.shenhe = true;
axios.post('/api/confirmGame', {
game_id: selectedMatch.value.id,
confirm: verify.value,
......@@ -162,11 +169,14 @@ function confirmAction() {
if (data.status === "SUCCESS") {
console.log('success');
}
refresh();
})
.catch(function (error) {
console.log(error);
})
}
confirmLoading.value = false;
dialog.value = false;
}
</script>
\ No newline at end of file
......@@ -2,38 +2,38 @@
<div class="text-h4 headline">
比赛管理
</div>
<v-card class="game-info-card">
<v-card class="game-info-card" v-if="exist_season">
<v-container>
<!-- <v-card-title color="indigo">
提交比赛
</v-card-title> -->
<v-form ref="form" v-model="isValid">
<v-row no-gutters>
<v-col align-self="center">
<v-autocomplete variant="underlined" v-model="player1" label="姓名"
:rules="[rules.player_not_none, rules.player1]" :items="arr"></v-autocomplete>
</v-col>
<v-col cols="2" align-self="center">
<div class="text-h6" style="text-align: center;">VS</div>
</v-col>
<v-col align-self="center">
<v-autocomplete variant="underlined" v-model="player2" label="姓名"
:rules="[rules.player_not_none, rules.player2]" :items="arr"></v-autocomplete>
</v-col>
</v-row>
<v-row no-gutters>
<v-col align-self="center">
<v-select variant="underlined" v-model="score1" label="得分" :rules="[rules.score_not_none, rules.score1]"
:items="['0', '1', '2', '3', '4', '5']"></v-select>
</v-col>
<v-col cols="2" align-self="center">
<div class="text-h6" style="text-align: center;">:</div>
</v-col>
<v-col align-self="center">
<v-select variant="underlined" v-model="score2" label="得分" :rules="[rules.score_not_none, rules.score2]"
:items="['0', '1', '2', '3', '4', '5']"></v-select>
</v-col>
</v-row>
<v-row no-gutters>
<v-col align-self="center">
<v-autocomplete variant="underlined" v-model="player1" label="姓名"
:rules="[rules.player_not_none, rules.player1]" :items="arr"></v-autocomplete>
</v-col>
<v-col cols="2" align-self="center">
<div class="text-h6" style="text-align: center;">VS</div>
</v-col>
<v-col align-self="center">
<v-autocomplete variant="underlined" v-model="player2" label="姓名"
:rules="[rules.player_not_none, rules.player2]" :items="arr"></v-autocomplete>
</v-col>
</v-row>
<v-row no-gutters>
<v-col align-self="center">
<v-select variant="underlined" v-model="score1" label="得分" :rules="[rules.score_not_none, rules.score1]"
:items="['0', '1', '2', '3', '4', '5']"></v-select>
</v-col>
<v-col cols="2" align-self="center">
<div class="text-h6" style="text-align: center;">:</div>
</v-col>
<v-col align-self="center">
<v-select variant="underlined" v-model="score2" label="得分" :rules="[rules.score_not_none, rules.score2]"
:items="['0', '1', '2', '3', '4', '5']"></v-select>
</v-col>
</v-row>
<v-dialog>
<template v-slot:activator="{ props: activatorProps }">
<v-btn block v-bind="activatorProps" class="text-none mb-4" color="indigo" size="large" variant="outlined">
......@@ -80,9 +80,17 @@
</v-dialog>
<div>
<v-card class="mx-auto my-2" href="/lauched_games.html" width="95%" rel="noopener" target="_blank" title="已提交比赛"
<v-card v-if="exist_season" class="mx-auto my-2" href="/lauched_games.html" width="95%" rel="noopener" target="_blank" title="已提交比赛"
append-icon="mdi-chevron-right"></v-card>
<v-card class="mx-auto my-2" href="/audit_games.html" width="95%" rel="noopener" target="_blank" title="待审核比赛"
<v-card v-if="exist_season" class="mx-auto my-2" href="/audit_games.html" width="95%" rel="noopener" target="_blank" title="待审核比赛">
<template v-slot:append>
<v-icon v-if="unaudit_number === 0">mdi-chevron-right</v-icon>
<v-badge v-if="unaudit_number !== 0" color="error" :content="unaudit_number" inline></v-badge>
</template>
</v-card>
<v-card v-if="exist_season" class="mx-auto my-2" href="/score_ranking.html" width="95%" rel="noopener" target="_blank" title="球员积分榜单"
append-icon="mdi-chevron-right"></v-card>
<v-card class="mx-auto my-2" href="/my_recentgames.html" width="95%" rel="noopener" target="_blank" title="比赛列表"
append-icon="mdi-chevron-right"></v-card>
</div>
......@@ -106,6 +114,8 @@ const id = ref(null);
const form = ref(null);
const form1 = ref(null);
const form2 = ref(null);
const unaudit_number = ref(0);
const exist_season = ref(false);
var s1;
var s2;
var p1_id;
......@@ -129,32 +139,37 @@ const rules = reactive({
// 监听 player1 的变化,并更新 player2 的验证规则
watch(player1, (newVal, oldVal) => {
if (newVal !== oldVal) {
form.value.validate(); // 触发表单验证
}
if (newVal !== oldVal) {
form.value.validate(); // 触发表单验证
}
});
watch(player2, (newVal, oldVal) => {
if (newVal !== oldVal) {
form.value.validate(); // 触发表单验证
}
if (newVal !== oldVal) {
form.value.validate(); // 触发表单验证
}
});
watch(score1, (newVal, oldVal) => {
if (newVal !== oldVal) {
form.value.validate(); // 触发表单验证
}
if (newVal !== oldVal) {
form.value.validate(); // 触发表单验证
}
});
watch(score2, (newVal, oldVal) => {
if (newVal !== oldVal) {
form.value.validate(); // 触发表单验证
}
if (newVal !== oldVal) {
form.value.validate(); // 触发表单验证
}
});
axios.get('/api/players')
axios.get('/api/players',{
params:{
lim: 1000,
}
})
.then(function (response) {
const data = response.data;
exist_season.value = data.ExistSeason;
for (var i = 0; i < data.Players.length; i++) {
arr.value[i] = data.Players[i].player_id.toString() + '-' + data.Players[i].player_real_name;
}
......@@ -163,6 +178,15 @@ axios.get('/api/players')
console.log(error);
})
axios.get('/api/lauchedGames',)
.then(function (response) {
const data1 = response.data;
unaudit_number.value = data1.Games.length;
})
.catch(function (error) {
console.log(error);
})
function submit() {
loading.value = true;
p1_id = parseInt(player1.value);
......@@ -184,9 +208,8 @@ function submit() {
game_date: selectedDate.value.toLocaleDateString(),
})
.then(function (response) {
const data = response.data;
console.log(data)
if (data.status == 'SUCCESS') {
const data2 = response.data;
if (data2.status == 'SUCCESS') {
info('提交成功!', "");
}
})
......@@ -220,7 +243,5 @@ function info(title, text) {
margin-left: 5%;
margin-top: 5%;
margin-bottom: 2%;
}
</style>
\ No newline at end of file
This diff is collapsed.
......@@ -66,6 +66,15 @@ const isValid = ref(false);
const realname1 = ref(false);
const loading = ref(false);
const cardtitle = ref(null);
const cardtext = ref(null);
const dialog = ref(false);
function info(title, text) {
cardtitle.value = title;
cardtext.value = text;
dialog.value = true;
}
function login() {
loading.value = true;
axios.post('/api/login', {
......@@ -77,9 +86,9 @@ function login() {
// console.log(data.is_member);
// console.log(data.is_member == 0);
if (data.status == 'SUCCESS') {
if (data.status === 'SUCCESS') {
if (data.is_su) {
// window.location.href = '/main.html';
window.location.href = '/main.html';
// console.log("su");
}
else if (data.is_member) {
......@@ -89,10 +98,16 @@ function login() {
else if (!data.is_member) {
// console.log("not member");
// console.log(realname1);
window.location.href = '/main.html';
// window.location.href = '/main.html';
realname1.value = true;
}
}
else if(data.status === 'USER_NOT_EXIST'){
info('用户不存在!');
}
else if(data.status === 'AUTHENTICATION_FAILED'){
info('密码错误!');
}
})
.catch(function (error) {
console.log(error);
......@@ -114,13 +129,4 @@ function submit() {
loading.value = false;
}
const cardtitle = ref(null);
const cardtext = ref(null);
const dialog = ref(false);
function info(title, text) {
cardtitle.value = title;
cardtext.value = text;
dialog.value = true;
}
</script>
\ No newline at end of file
<template>
<v-card
class="ma-6"
>
<v-list density="comfortable">
<v-list-subheader>快捷审核</v-list-subheader>
<v-list-item
color="primary"
href="/user_audit.html"
height="60px"
appendIcon = "mdi-chevron-right"
>
<v-list-item-title class="text-h6">用户入会审核</v-list-item-title>
</v-list-item>
<v-list-item
color="primary"
href="/player_audit.html"
height="60px"
appendIcon = "mdi-chevron-right"
>
<v-list-item-title class="text-h6">球员加入赛季审核</v-list-item-title>
</v-list-item>
<v-divider></v-divider>
<v-list-subheader>赛季管理</v-list-subheader>
<v-list-item
color="primary"
href="/season_manage.html"
height="60px"
appendIcon = "mdi-chevron-right"
>
<v-list-item-title class="text-h6">开启/关闭赛季</v-list-item-title>
</v-list-item>
<v-list-item
color="primary"
href="/player_manage.html"
height="60px"
appendIcon = "mdi-chevron-right"
>
<v-list-item-title class="text-h6">球员信息维护</v-list-item-title>
</v-list-item>
<v-divider></v-divider>
<v-list-subheader>基础数据维护</v-list-subheader>
<v-list-item
color="primary"
href="/user_manage.html"
height="60px"
appendIcon = "mdi-chevron-right"
>
<v-list-item-title class="text-h6">用户管理</v-list-item-title>
</v-list-item>
<v-list-item
color="primary"
href="/game_manage.html"
height="60px"
appendIcon = "mdi-chevron-right"
>
<v-list-item-title class="text-h6">比赛管理</v-list-item-title>
</v-list-item>
</v-list>
</v-card>
<!-- <div class="text-h4 headline">
快捷审核
</div>
<v-card class="mx-auto my-2" href="/user_audit.html" width="95%" rel="noopener" target="_blank" title="用户入会审核"
append-icon="mdi-chevron-right"></v-card>
<v-card class="mx-auto my-2" href="/player_audit.html" width="95%" rel="noopener" target="_blank" title="球员加入赛季审核"
append-icon="mdi-chevron-right"></v-card>
<div class="text-h4 headline">
赛季管理
</div>
<v-card class="mx-auto my-2" href="/season_manage.html" width="95%" rel="noopener" target="_blank" title="开启/关闭赛季"
append-icon="mdi-chevron-right"></v-card>
<v-card class="mx-auto my-2" href="/player_manage.html" width="95%" rel="noopener" target="_blank" title="球员信息维护"
append-icon="mdi-chevron-right"></v-card>
<div class="text-h4 headline">
基础数据维护
</div>
<v-card class="mx-auto my-2" href="/user_manage.html" width="95%" rel="noopener" target="_blank" title="用户管理"
append-icon="mdi-chevron-right"></v-card>
<v-card class="mx-auto my-2" href="/game_manage.html" width="95%" rel="noopener" target="_blank" title="比赛管理"
append-icon="mdi-chevron-right"></v-card> -->
</template>
<style>
.title-size {
margin-left: 5%;
margin-top: 10%;
margin-bottom: 2%;
}
</style>
\ No newline at end of file
This diff is collapsed.
......@@ -8,7 +8,7 @@
import { registerPlugins } from '@/plugins'
// Components
import App from './home.vue'
import App from './game_manage.vue'
// Composables
import { createApp } from 'vue'
......
This diff is collapsed.
<!-- <script setup>
import Dialog from './components/dialog.vue';
import { ref } from 'vue';
const count = ref(0)
const info = ref(0)
function testclick() {
count.value++
info.value=count.value
}
</script>
<template>
<v-app>
<v-main>
<Dialog class="dialog" ></Dialog>
<v-btn @click="testclick">
</v-btn>
<div>{{ info }}</div>
</v-main>
</v-app>
</template>
-->
<script setup>
// import { ref } from 'vue';
// const tab = ref(null)
// const text = ref('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.')
// export default {
// data () {
// return {
// tab: null,
// text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',
// }
// },
// }
</script>
<template>
<!-- <div>发起比赛</div> -->
</template>
<style>
.main-card{
height: 100%;
width: 100%;
}
.tabs{
width: 100%;
position: fixed;
bottom: 0;
}
</style>
\ No newline at end of file
<!-- <script setup>
import Dialog from './components/dialog.vue';
import { ref } from 'vue';
const count = ref(0)
const info = ref(0)
function testclick() {
count.value++
info.value=count.value
}
</script>
<template>
<v-app>
<v-main>
<Dialog class="dialog" ></Dialog>
<v-btn @click="testclick">
</v-btn>
<div>{{ info }}</div>
</v-main>
</v-app>
</template>
-->
<script setup>
// import { ref } from 'vue';
// const tab = ref(null)
// const text = ref('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.')
// export default {
// data () {
// return {
// tab: null,
// text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',
// }
// },
// }
</script>
<template>
<!-- <div>首页</div> -->
</template>
<style>
.main-card{
height: 100%;
width: 100%;
}
.tabs{
width: 100%;
position: fixed;
bottom: 0;
}
</style>
\ No newline at end of file
<template>
<v-app>
<v-data-table :headers="headers" :items="filteredMatches" item-key="id" :search="search.value"
:items-per-page="10">
<v-data-table-server :headers="headers" :items="filteredMatches" item-key="id" :search="search"
v-model:items-per-page="itemsPerPage" @update:options="loadGames" :items-length="totalGames"
:loading="loading">
<template v-slot:top>
<v-toolbar flat>
<v-toolbar-title>比赛</v-toolbar-title>
......@@ -12,7 +13,7 @@
</v-toolbar>
</template>
<template v-slot:item.date="{ item }">
<p style="width:60px" >{{ item.date }}</p>
<p style="width:60px">{{ item.date }}</p>
</template>
<template v-slot:item.name="{ item }">
<p style="width:120px">{{ item.username }} VS {{ item.opponentname }}</p>
......@@ -22,10 +23,11 @@
</template>
<template v-slot:item.verified="{ item }">
<div style="width:80px"><v-icon v-if="item.verified === 'WAITING'" color="blue">mdi-help-circle</v-icon>
<v-icon v-else-if="item.verified === 'PASSED'" color="green">mdi-check-circle</v-icon>
<v-icon v-else-if="item.verified === 'REJECT'" color="red">mdi-close-circle</v-icon></div>
<v-icon v-else-if="item.verified === 'PASSED'" color="green">mdi-check-circle</v-icon>
<v-icon v-else-if="item.verified === 'REJECT'" color="red">mdi-close-circle</v-icon>
</div>
</template>
</v-data-table>
</v-data-table-server>
</v-app>
</template>
......@@ -44,6 +46,9 @@ const headers = reactive([
{ title: '审核状态', key: 'verified' },
]);
const matches = ref(new Array());
const loading = ref(true);
const totalGames = ref(0);
const itemsPerPage = ref(5);
// matches = [
// { id: 1, username: '张三', opponentname: '零', userScore: 3, opponentScore: 2, verified: "PASSED" },
// ];
......@@ -58,24 +63,37 @@ const filteredMatches = computed(() => {
);
})
axios.get('/api/myLauchedGames',)
.then(function(response){
const data = response.data;
for(var i = 0; i < data.Games.length; i++){
// matches.value[i].id = i+1;
var match = {
id:data.Games[i].id,
date:data.Games[i].game_date,
username:data.Games[i].player1_real_name,
opponentname:data.Games[i].player2_real_name,
userScore:data.Games[i].score1,
opponentScore:data.Games[i].score2,
verified:data.Games[i].status,
}
matches.value[i] = match;
function loadGames({ page, itemsPerPage }) {
axios.get('/api/myLauchedGames',{
params:{
pages: page,
lim: itemsPerPage,
}
})
.catch(function (error) {
console.log(error);
})
.then(function (response) {
loading.value = true;
const data = response.data;
totalGames.value = data.totalGames;
matches.value.length = 0;
for (var i = 0; i < data.Games.length; i++) {
// matches.value[i].id = i+1;
var match = {
id: data.Games[i].id,
date: data.Games[i].game_date,
username: data.Games[i].player1_real_name,
opponentname: data.Games[i].player2_real_name,
userScore: data.Games[i].score1,
opponentScore: data.Games[i].score2,
verified: data.Games[i].status,
}
matches.value[i] = match;
}
loading.value = false;
})
.catch(function (error) {
console.log(error);
})
}
</script>
\ No newline at end of file
<template>
<div class="h-screen w-auto">
<v-window v-model="tab" class="h-screen w-auto bottom-navigation">
<div class="w-auto">
<v-window v-model="tab" class="h-screen w-auto">
<v-window-item :key="1" :value="'tab-1'" class="h-screen w-100 bottom-navigation">
<Home></Home>
</v-window-item>
......@@ -10,17 +10,23 @@
<v-window-item :key="3" :value="'tab-3'" class="h-screen w-100 bottom-navigation">
<Space></Space>
</v-window-item>
<v-window-item :key="4" :value="'tab-4'" class="h-screen w-100 bottom-navigation">
<Manage></Manage>
</v-window-item>
</v-window>
<v-layout class="overflow-visible" style="height: 56px;">
<v-layout class="tabs">
<v-bottom-navigation v-model="tab" color="indigo" align-tabs="center" stacked grow class="tabs">
<v-bottom-navigation v-model="tab" color="indigo" align-tabs="center" stacked grow>
<v-btn value="tab-1">
<v-icon>mdi-home</v-icon>
首页
</v-btn>
<v-btn value="tab-2">
<v-icon>mdi-table-tennis</v-icon>
<v-badge color="error" dot v-if="unaudit_number !== 0">
<v-icon>mdi-table-tennis</v-icon>
</v-badge>
<v-icon v-if="unaudit_number === 0">mdi-table-tennis</v-icon>
比赛
</v-btn>
......@@ -28,6 +34,11 @@
<v-icon>mdi-account</v-icon>
我的
</v-btn>
<v-btn v-if="is_su" value="tab-4">
<v-icon>mdi-account-cog</v-icon>
管理
</v-btn>
</v-bottom-navigation>
</v-layout>
......@@ -39,8 +50,31 @@ import { ref } from 'vue';
import Gamemanage from './components/gamemanage.vue';
import Space from './components/space.vue';
import Home from './components/home.vue';
import Manage from './components/manage.vue';
import axios from 'axios';
const tab = ref(null);
const is_su = ref(false);
const unaudit_number = ref(0);
axios.get('/api/currentUser')
.then(function (response) {
const data = response.data;
is_su.value = data.is_su;
})
.catch(function (error) {
console.log(error);
})
axios.get('/api/lauchedGames',)
.then(function (response) {
const data1 = response.data;
unaudit_number.value = data1.Games.length;
})
.catch(function (error) {
console.log(error);
})
const tab = ref(null)
</script>
<style>
......@@ -49,12 +83,15 @@ const tab = ref(null)
position: fixed;
bottom: 0;
z-index: 100;
height: 56px;
}
.bottom-navigation {
overflow-y: auto;
padding-bottom: 57px;
padding-bottom: 70px;
box-sizing: border-box;
}
/*.main-card{
height: 100%;
width: 100%;
......
/**
* main.js
*
* Bootstraps Vuetify and other plugins then mounts the App`
*/
// Plugins
import { registerPlugins } from '@/plugins'
// Components
import App from './my_recentgames.vue'
// Composables
import { createApp } from 'vue'
const app = createApp(App)
registerPlugins(app)
app.mount('#app')
<template>
<v-app>
<v-data-table-server :headers="headers" v-model:items-per-page="itemsPerPage" :items="filteredMatches"
item-key="id" :search="search" :items-length="totalGames" @update:options="loadGames" :loading="loading">
<template v-slot:top>
<v-toolbar flat>
<v-toolbar-title>比赛列表</v-toolbar-title>
<v-divider class="mx-3" inset vertical></v-divider>
<v-spacer></v-spacer>
<v-text-field v-model="search" append-icon="mdi-magnify" label="搜索" single-line
hide-details></v-text-field>
</v-toolbar>
<v-form v-model="isValid">
<div class="d-flex justify-space-around align-center">
<div>
<v-autocomplete :rules="[rules.season_not_none]" style="width: 150px;" variant="underlined" v-model="selectSeason"
:items="arr" label="选择赛季"></v-autocomplete>
</div>
<div>
<v-btn :disabled="!isValid" @click="getSeasonInfo" color="indigo" style="width: 80px;" text="确定"></v-btn>
</div>
</div>
</v-form>
</template>
<template v-slot:item.date="{ item }">
<p style="width:60px">{{ item.date }}</p>
</template>
<template v-slot:item.name="{ item }">
<p style="width:120px">{{ item.homeTeam }} VS {{ item.awayTeam }}</p>
</template>
<template v-slot:item.score="{ item }">
<p style="width:30px">{{ item.homeScore }} - {{ item.awayScore }}</p>
</template>
</v-data-table-server>
</v-app>
</template>
<script setup>
import { ref } from 'vue';
import { reactive } from 'vue';
import { computed } from 'vue';
import axios from 'axios';
const search = ref('');
var my_idstr = window.location.search;
const my_id = extractNumbers(my_idstr)[0];
const itemsPerPage = ref(5);
const totalGames = ref(0);
const loading = ref(true);
const selectSeason = ref(null);
const arr = ref(new Array());
const isValid = ref(false);
const headers = reactive([
{ title: '日期', key: 'date', sortable: false },
{ title: '比赛', key: 'name', sortable: false },
{ title: '比分', key: 'score', sortable: false },
]);
const matches = ref(new Array());
// matches = [
// { id: 1, username: '张三', opponentname: '零', userScore: 3, opponentScore: 2, verified: "PASSED" },
// ];
function extractNumbers(str) {
const pattern = /\d+/g;
const matches = str.match(pattern);
return matches ? matches.map(Number) : [];
}
const filteredMatches = computed(() => {
// return matches.value
return matches.value.filter(match =>
match.homeTeam.includes(search.value) ||
match.awayTeam.includes(search.value) ||
match.homeScore === parseInt(search.value) ||
match.awayScore === parseInt(search.value) ||
match.date.includes(search.value)
);
})
const rules = reactive({
email: v => !!(v || '').match(/@/) || 'Please enter a valid email',
length: len => v => (v || '').length >= len || `Invalid character length, required ${len}`,
season_not_none: v => !!v || '赛季不能为空',
});
axios.get('/api/seasonInfo')
.then(function (response) {
const data = response.data;
if (data.selectSeason.season_id !== -1) {
selectSeason.value = data.selectSeason.season_id.toString() + '-' + data.selectSeason.season_name;
}
for (var i = 0; i < data.Seasons.length; i++) {
arr.value[i] = data.Seasons[i].season_id.toString() + '-' + data.Seasons[i].season_name;
}
})
.catch(function (error) {
console.log(error);
})
function getSeasonInfo() {
loadGames({ page: 1, itemsPerPage: itemsPerPage.value });
}
function loadGames({ page, itemsPerPage }) {
loading.value = true;
if (selectSeason.value !== null) {
axios.get('/api/games', {
params: {
pages: page,
lim: itemsPerPage,
myid: my_id,
season_id: parseInt(selectSeason.value),
}
})
.then(function (response) {
const data2 = response.data;
matches.value.length = 0;
totalGames.value = data2.totalGames;
for (var i = 0; i < data2.Games.length; i++) {
var match = {
id: data2.Games[i].id,
date: 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,
}
matches.value[i] = match;
}
loading.value = false
})
.catch(function (error) {
console.log(error);
})
}
else {
axios.get('/api/games', {
params: {
pages: page,
lim: itemsPerPage,
myid: my_id,
}
})
.then(function (response) {
const data2 = response.data;
matches.value.length = 0;
totalGames.value = data2.totalGames;
for (var i = 0; i < data2.Games.length; i++) {
var match = {
id: data2.Games[i].id,
date: 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,
}
matches.value[i] = match;
}
loading.value = false
})
.catch(function (error) {
console.log(error);
})
}
}
// axios.get('/api/myLauchedGames',)
// .then(function(response){
// const data = response.data;
// for(var i = 0; i < data.Games.length; i++){
// // matches.value[i].id = i+1;
// var match = {
// id:data.Games[i].id,
// date:data.Games[i].game_date,
// username:data.Games[i].player1_real_name,
// opponentname:data.Games[i].player2_real_name,
// userScore:data.Games[i].score1,
// opponentScore:data.Games[i].score2,
// verified:data.Games[i].status,
// }
// matches.value[i] = match;
// }
// })
// .catch(function (error) {
// console.log(error);
// })
</script>
\ No newline at end of file
/**
* main.js
*
* Bootstraps Vuetify and other plugins then mounts the App`
*/
// Plugins
import { registerPlugins } from '@/plugins'
// Components
import App from './past_seasons.vue'
// Composables
import { createApp } from 'vue'
const app = createApp(App)
registerPlugins(app)
app.mount('#app')
<template>
<v-app>
<v-data-table-server :headers="headers" v-model:items-per-page="itemsPerPage" :items="filteredMatches"
item-key="id" :search="search" :items-length="totalGames" @update:options="loadGames" :loading="loading">
<template v-slot:top>
<v-toolbar flat>
<v-toolbar-title>过往赛季</v-toolbar-title>
<v-divider class="mx-3" inset vertical></v-divider>
<v-spacer></v-spacer>
<v-text-field v-model="search" append-icon="mdi-magnify" label="搜索" single-line
hide-details></v-text-field>
</v-toolbar>
<div class="d-flex justify-space-around align-center" style="height: 60px;">
<div>
<v-autocomplete style="width: 150px;" variant="underlined" v-model="selectSeason" :items="arr"
label="选择赛季"></v-autocomplete>
</div>
<div>
<v-btn color="indigo" style="width: 80px;" text="确定"></v-btn>
</div>
</div>
</template>
<template v-slot:item.date="{ item }">
<p style="width:60px">{{ item.date }}</p>
</template>
<template v-slot:item.name="{ item }">
<p style="width:120px">{{ item.homeTeam }} VS {{ item.awayTeam }}</p>
</template>
<template v-slot:item.score="{ item }">
<p style="width:30px">{{ item.homeScore }} - {{ item.awayScore }}</p>
</template>
</v-data-table-server>
</v-app>
</template>
<script setup>
import { ref } from 'vue';
import { reactive } from 'vue';
import { computed } from 'vue';
import axios from 'axios';
const search = ref('');
const itemsPerPage = ref(5);
const totalGames = ref(0);
const loading = ref(true);
const selectSeason = ref(null);
const arr = ref(new Array());
const headers = reactive([
{ title: '日期', key: 'date', sortable: false },
{ title: '比赛', key: 'name', sortable: false },
{ title: '比分', key: 'score', sortable: false },
]);
const matches = ref(new Array());
const filteredMatches = computed(() => {
// return matches.value
return matches.value.filter(match =>
match.homeTeam.includes(search.value) ||
match.awayTeam.includes(search.value) ||
match.homeScore === parseInt(search.value) ||
match.awayScore === parseInt(search.value) ||
match.date.includes(search.value)
);
})
axios.get('/api/seasonInfo')
.then(function (response) {
const data = response.data;
for (var i = 0; i < data.Seasons.length; i++) {
arr.value[i] = data.Seasons[i].season_id.toString() + '-' + data.Seasons[i].season_name;
}
})
.catch(function (error) {
console.log(error);
})
function getSeasonInfo(){
}
function loadGames({ page, itemsPerPage }) {
loading.value = true;
axios.get('/api/games', {
params: {
pages: page,
lim: itemsPerPage,
}
})
.then(function (response) {
const data2 = response.data;
matches.value.length = 0;
totalGames.value = data2.totalGames;
for (var i = 0; i < data2.Games.length; i++) {
var match = {
id: data2.Games[i].id,
date: 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,
}
matches.value[i] = match;
}
loading.value = false
})
.catch(function (error) {
console.log(error);
})
}
</script>
\ No newline at end of file
/**
* main.js
*
* Bootstraps Vuetify and other plugins then mounts the App`
*/
// Plugins
import { registerPlugins } from '@/plugins'
// Components
import App from './player_audit.vue'
// Composables
import { createApp } from 'vue'
const app = createApp(App)
registerPlugins(app)
app.mount('#app')
<template>
<v-app>
<v-data-table :loading="loading" :headers="headers" :items="players" item-key="id" :search="search" :items-per-page="5">
<template v-slot:top>
<v-toolbar flat>
<v-toolbar-title>球员审核</v-toolbar-title>
<v-divider class="mx-3" inset vertical></v-divider>
<v-spacer></v-spacer>
<v-text-field v-model="search" append-icon="mdi-magnify" label="搜索" single-line
hide-details></v-text-field>
</v-toolbar>
</template>
<template v-slot:item.player_id="{ item }">
<p v-if="item.player_id" style="width:50px">{{ item.player_id }}</p>
</template>
<template v-slot:item.player_real_name="{ item }">
<p v-if="item.player_real_name" style="width:50px">{{ item.player_real_name }}</p>
</template>
<template v-slot:item.actions="{ item }">
<v-icon @click="editPlayer(item)" style="width:50px">mdi-pencil</v-icon>
</template>
</v-data-table>
</v-app>
<v-dialog v-model="dialog" width="auto">
<v-card width="300px">
<v-card-title>
审核球员信息
</v-card-title>
<v-card-text>
<v-form v-model="isValid">
<p variant="filled" style="margin-bottom: 20px;">姓名:{{ selectPlayer.player_real_name }}</p>
<v-select v-model="selectPlayer.group" :rules="[rules.group]" :items="['A组', 'B组', 'C组']"
variant="filled" color="indigo" label="分组"></v-select>
</v-form>
</v-card-text>
<template v-slot:actions>
<v-btn :disabled="!isValid" :loading="playerLoading" class="ms-auto" variant="flat" color="indigo" text="确定" @click="changePlayer"></v-btn>
</template>
</v-card>
</v-dialog>
<v-dialog v-model="dialog1" 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>
</template>
<script setup>
import { ref } from 'vue';
import { reactive } from 'vue';
// import { computed } from 'vue';
import axios from 'axios';
const search = ref('');
// const actions_text = ref('');
const headers = reactive([
{ title: 'ID', key: 'player_id' },
{ title: '姓名', key: 'player_real_name' },
{ title: '编辑', key: 'actions' },
]);
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 || '用户名不能为空',
realname: v => !!v || '姓名不能为空',
confirmpassword: v => v === password.value || '密码不匹配',
password: v => !!v || '密码不能为空',
su: v => !!v || '管理员不能为空',
member: v => !!v || '会员不能为空',
group: 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',
});
const isValid = ref(false);
const loading = ref(true);
const playerLoading = ref(false);
const players = ref(new Array());
const dialog = ref(false);
const selectPlayer = ref({
player_id: 0,
player_real_name: '',
group: '',
group_number: 0,
});
const cardtitle = ref(null);
const cardtext = ref(null);
const dialog1 = ref(false);
function info(title, text) {
cardtitle.value = title;
cardtext.value = text;
dialog1.value = true;
}
function refresh() {
loading.value = true;
axios.get('/api/getPlayers')
.then(function (response) {
const data = response.data;
players.value.length = 0;
for (var i = 0; i < data.unaudited_season_playersInfo.length; i++) {
const player = ref({
player_id: data.unaudited_season_playersInfo[i].player_id,
player_real_name: data.unaudited_season_playersInfo[i].player_real_name,
})
players.value[i] = player;
}
})
.catch(function (error) {
console.log(error);
})
loading.value = false;
}
refresh();
function editPlayer(item) {
dialog.value = true;
selectPlayer.value = item;
}
function changePlayer() {
playerLoading.value = true;
if (selectPlayer.value.group === 'A组'){
selectPlayer.value.group_number = 1;
}
if (selectPlayer.value.group === 'B组'){
selectPlayer.value.group_number = 2;
}
if (selectPlayer.value.group === 'C组'){
selectPlayer.value.group_number = 3;
}
axios.post('/api/playerAudit', selectPlayer.value)
.then(function (response) {
const data1 = response.data;
if (data1.status === "FAILED") {
info("修改失败!", "");
}
dialog.value = false;
refresh();
})
.catch(function (error) {
console.log(error);
})
playerLoading.value = false;
}
</script>
\ No newline at end of file
/**
* main.js
*
* Bootstraps Vuetify and other plugins then mounts the App`
*/
// Plugins
import { registerPlugins } from '@/plugins'
// Components
import App from './player_manage.vue'
// Composables
import { createApp } from 'vue'
const app = createApp(App)
registerPlugins(app)
app.mount('#app')
<template>
<v-app>
<v-data-table :loading="loading" :headers="headers" :items="players" item-key="id" :search="search" :items-per-page="5">
<template v-slot:top>
<v-toolbar flat>
<v-toolbar-title>球员管理</v-toolbar-title>
<v-divider class="mx-3" inset vertical></v-divider>
<v-spacer></v-spacer>
<v-text-field v-model="search" append-icon="mdi-magnify" label="搜索" single-line
hide-details></v-text-field>
</v-toolbar>
</template>
<template v-slot:item.player_id="{ item }">
<p v-if="item.player_id" style="width:50px">{{ item.player_id }}</p>
</template>
<template v-slot:item.player_real_name="{ item }">
<p v-if="item.player_real_name" style="width:50px">{{ item.player_real_name }}</p>
</template>
<template v-slot:item.group="{ item }">
<p v-if="item.group" style="width:50px">{{ item.group }}</p>
</template>
<template v-slot:item.score="{ item }">
<p style="width:50px">{{ item.score }}</p>
</template>
<template v-slot:item.total_games="{ item }">
<p style="width:50px">{{ item.total_games }}</p>
</template>
<template v-slot:item.winrate="{ item }">
<p style="width:50px">{{ item.winrate }}%</p>
</template>
<template v-slot:item.actions="{ item }">
<v-icon @click="editPlayer(item)" style="width:50px">mdi-pencil</v-icon>
</template>
</v-data-table>
</v-app>
<v-dialog v-model="dialog" width="auto">
<v-card width="300px">
<v-card-title>
编辑用户信息
</v-card-title>
<v-card-text>
<v-form v-model="isValid">
<p variant="filled" style="margin-bottom: 20px;">姓名:{{ selectPlayer.player_real_name }}</p>
<v-select v-model="selectPlayer.group" :rules="[rules.group]" variant="filled" :items="['A组', 'B组', 'C组']"
color="indigo" label="分组"></v-select>
<v-text-field type="number" v-model="selectPlayer.score" :rules="[rules.score_not_none ,rules.score]" variant="filled"
color="indigo" label="积分"></v-text-field>
<v-text-field type="number" v-model="selectPlayer.total_games" :rules="[rules.totalgames_not_none,rules.totalgames]"
variant="filled" color="indigo" label="场次"></v-text-field>
</v-form>
</v-card-text>
<template v-slot:actions>
<v-btn :disabled="!isValid" :loading="PlayerLoading" class="ms-auto" variant="flat" color="indigo" text="修改" @click="changePlayer"></v-btn>
</template>
</v-card>
</v-dialog>
<v-dialog v-model="dialog1" 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>
</template>
<script setup>
import { ref } from 'vue';
import { reactive } from 'vue';
// import { computed } from 'vue';
import axios from 'axios';
const search = ref('');
// const actions_text = ref('');
const headers = reactive([
{ title: 'ID', key: 'player_id' },
{ title: '姓名', key: 'player_real_name' },
{ title: '分组', key: 'group' },
{ title: '积分', key: 'score' },
{ title: '场次', key: 'total_games' },
{ title: '胜率', key: 'winrate' },
{ title: '编辑', key: 'actions' },
]);
const rules = reactive({
email: v => !!(v || '').match(/@/) || 'Please enter a valid email',
length: len => v => (v || '').length >= len || `Invalid character length, required ${len}`,
// score: v => !!v || '积分不能为空',
// totalgames: v => !!v || '场次不能为空',
group: v => !!v || '分组不能为空',
score_not_none: v => /^[0-9]\d*$/.test(v) || '积分应为非负整数',
totalgames_not_none: v => /^[0-9]\d*$/.test(v) || '场次应为非负整数',
score: v => (Number(v) <= selectPlayer.value.total_games)|| '积分应小于等于场次',
totalgames: v => (Number(v) >= selectPlayer.value.score)|| '场次应大于等于积分',
// password: v => !!v || '密码不能为空',
// su: v => !!v || '管理员不能为空',
// member: 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',
});
const isValid = ref(false);
const PlayerLoading = ref(false);
const loading = ref(true);
const players = ref(new Array());
const dialog = ref(false);
const selectPlayer = ref({
player_id: 0,
player_real_name: '',
score: 0,
group: '',
group_number: 0,
total_games: 0,
winrate: 0,
});
const cardtitle = ref(null);
const cardtext = ref(null);
const dialog1 = ref(false);
function info(title, text) {
cardtitle.value = title;
cardtext.value = text;
dialog1.value = true;
}
function refresh() {
loading.value = true;
axios.get('/api/getPlayers')
.then(function (response) {
const data = response.data;
players.value.length = 0;
for (var i = 0; i < data.season_playersInfo.length; i++) {
const player = ref({
player_id: data.season_playersInfo[i].player_id,
player_real_name: data.season_playersInfo[i].player_real_name,
group_number: data.season_playersInfo[i].group,
score: data.season_playersInfo[i].score,
total_games: data.season_playersInfo[i].total_games,
winrate: data.season_playersInfo[i].winrate,
group: '',
})
if (player.value.group_number === 1){
player.value.group = 'A组'
}
if (player.value.group_number === 2){
player.value.group = 'B组'
}
if (player.value.group_number === 3){
player.value.group = 'C组'
}
players.value[i] = player;
}
})
.catch(function (error) {
console.log(error);
})
loading.value = false;
}
refresh();
function editPlayer(item) {
dialog.value = true;
selectPlayer.value = item;
}
function changePlayer() {
PlayerLoading.value = true;
if (selectPlayer.value.group === 'A组'){
selectPlayer.value.group_number = 1
}
if (selectPlayer.value.group === 'B组'){
selectPlayer.value.group_number = 2
}
if (selectPlayer.value.group === 'C组'){
selectPlayer.value.group_number = 3
}
selectPlayer.value.score = Number(selectPlayer.value.score)
selectPlayer.value.total_games = Number(selectPlayer.value.total_games)
axios.post('/api/playerManage', selectPlayer.value)
.then(function (response) {
const data1 = response.data;
if (data1.status === "FAILED") {
info("修改失败!", "");
}
dialog.value = false;
refresh();
})
.catch(function (error) {
console.log(error);
})
PlayerLoading.value = false;
}
</script>
\ No newline at end of file
/**
* main.js
*
* Bootstraps Vuetify and other plugins then mounts the App`
*/
// Plugins
import { registerPlugins } from '@/plugins'
// Components
import App from './score_ranking.vue'
// Composables
import { createApp } from 'vue'
const app = createApp(App)
registerPlugins(app)
app.mount('#app')
<template>
<div class="score-card">
<v-card v-if="players.length" elevation="5">
<template v-slot:prepend>
<v-icon size="25px">mdi-medal</v-icon>
</template>
<template v-slot:title>
<div class="text-h6">积分榜单</div>
</template>
<v-infinite-scroll mode="manual" @load="load">
<v-list>
<v-list-item v-for="(player, index) in players" :key="index" :value="players"
@click="goto_space(player.player_id)">
<template v-slot:default>
<div class="d-flex justify-space-between align-center game-item">
<div>
<v-avatar size="48px"><img :src="player.avatar" class="avatar-img"></v-avatar>
</div>
<div class="realname-text">{{ player.realname }}</div>
<div class="winrate-text">{{ player.winrate }}%</div>
<div class="name-score">{{ player.games }}</div>
<div class="date-text">{{ player.point }}</div>
<v-icon>mdi-chevron-right</v-icon>
</div>
</template>
</v-list-item>
</v-list>
</v-infinite-scroll>
</v-card>
</div>
</template>
<script setup>
import { ref } from 'vue';
// import { reactive } from 'vue';
// import { computed } from 'vue';
import axios from 'axios';
const players = ref(new Array());
const pages = ref(1);
function refresh() {
axios.get("/api/players", {
params: {
pages: pages.value,
}
})
.then(function (response) {
const data1 = response.data;
// players.value.length = 0;
for (var i = 0; i < data1.Players.length; i++) {
var player = {
number: i + 1,
player_id: data1.Players[i].player_id,
realname: data1.Players[i].player_real_name,
games: data1.Players[i].total_games,
point: data1.Players[i].score,
winrate: data1.Players[i].winrate,
avatar: data1.Players[i].player_profile_file,
}
players.value.push(player);
}
})
.catch(function (error) {
console.log(error);
})
}
refresh();
function goto_space(my_id) {
window.location.href = '/space.html?myid=' + my_id;
}
async function api() {
pages.value += 1;
refresh();
return players.value
}
async function load({ done }) {
const res = await api();
// console.log(res)
// players.value.push(res);
done('ok')
done('empty')
}
</script>
<style>
.score-card {
/* margin-top: 10px; */
margin: auto;
/* margin-top: 10px; */
padding-top: 10px;
width: 95%;
}
.avatar-img {
object-fit: cover;
width: 100%;
height: 100%;
}
.date-text {
font-size: small;
color: grey;
text-align: center;
padding-left: 7px;
padding-right: 7px;
}
.realname-text {
font-size: large;
font-weight: bold;
width: 72px;
text-align: center;
}
.winrate-text {
font-family: 'Times New Roman';
width: 40px;
text-align: center;
}
.name-score {
width: 20%;
text-align: center;
margin-left: 5px;
margin-right: 5px;
/* line-height: 33px; */
}
</style>
\ No newline at end of file
/**
* main.js
*
* Bootstraps Vuetify and other plugins then mounts the App`
*/
// Plugins
import { registerPlugins } from '@/plugins'
// Components
import App from './season_manage.vue'
// Composables
import { createApp } from 'vue'
const app = createApp(App)
registerPlugins(app)
app.mount('#app')
<template>
<v-app>
<v-data-table :loading="loading" :headers="headers" :items="seasons" item-key="id" :search="search" :items-per-page="5">
<template v-slot:top>
<v-toolbar flat>
<v-toolbar-title>赛季管理</v-toolbar-title>
<v-divider class="mx-3" inset vertical></v-divider>
<v-spacer></v-spacer>
<v-text-field v-model="search" append-icon="mdi-magnify" label="搜索" single-line
hide-details></v-text-field>
</v-toolbar>
</template>
<template v-slot:item.season_id="{ item }">
<p v-if="item.season_id" style="width:50px">{{ item.season_id }}</p>
</template>
<template v-slot:item.season_name="{ item }">
<p v-if="item.season_name" style="width:50px">{{ item.season_name }}</p>
</template>
<template v-slot:item.start_date="{ item }">
<p v-if="item.start_date" style="width:50px">{{ formatDate(item.start_date) }}</p>
</template>
<template v-slot:item.end_date="{ item }">
<p v-if="item.end_date" style="width:50px">{{ formatDate(item.end_date) }}</p>
</template>
<template v-slot:item.season_enable="{ item }">
<p v-if="item.season_enable" style="width:50px">{{ item.season_enable }}</p>
</template>
<template v-slot:item.actions="{ item }">
<v-btn v-if="item.season_enable" :loading="endLoading" @click="season_end(item)" style="width:50px" variant="text"
color="indigo" text="结束赛季"></v-btn>
<v-btn v-if="!item.season_enable" :loading="restartLoading" @click="season_restart(item)" style="width:50px" variant="text"
color="indigo" text="重启赛季"></v-btn>
</template>
</v-data-table>
<div><v-btn style="width: 100px;" class="float-right" variant="text" color="indigo"
prepend-icon="mdi-scoreboard" @click="dialog = true" text="开启赛季"></v-btn></div>
</v-app>
<v-dialog v-model="dialog" width="auto">
<v-card width="300px">
<v-card-title>
开启赛季
</v-card-title>
<v-card-text>
<v-form v-model="isValid">
<v-text-field v-model="new_season_name" variant="filled" color="indigo" label="赛季名" :rules="[rules.season]"></v-text-field>
<v-btn block @click="date_dialog = true" class="text-none mb-4" color="indigo" size="large"
variant="outlined">
<template v-slot:default>
选择赛季开始日期:{{ selectedDate.toLocaleDateString() }}
</template>
</v-btn>
</v-form>
</v-card-text>
<template v-slot:actions>
<v-btn :disabled="!isValid" :loading="startLoading" class="ms-auto" variant="flat" color="indigo" text="确定" @click="season_start"></v-btn>
</template>
</v-card>
</v-dialog>
<v-dialog v-model="date_dialog" width="auto">
<v-card>
<v-locale-provider locale="zhHans">
<v-date-picker v-model="selectedDate" header="日期" title="选择赛季开始日期" color="indigo"
width="100%"></v-date-picker>
</v-locale-provider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn variant="flat" text="确定" color="indigo" @click="date_dialog = false"></v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-dialog v-model="dialog1" 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>
</template>
<script setup>
import { ref } from 'vue';
import { reactive } from 'vue';
import axios from 'axios';
const search = ref('');
// const actions_text = ref('');
const headers = reactive([
{ title: 'ID', key: 'season_id' },
{ title: '赛季', key: 'season_name' },
{ title: '开始日期', key: 'start_date' },
{ title: '结束时间', key: 'end_date' },
{ title: '进行中', key: 'season_enable' },
// { title: '管理员', key: 'is_su' },
{ title: '操作', key: 'actions' },
]);
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 || '用户名不能为空',
realname: v => !!v || '姓名不能为空',
confirmpassword: v => v === password.value || '密码不匹配',
password: v => !!v || '密码不能为空',
su: v => !!v || '管理员不能为空',
member: v => !!v || '会员不能为空',
season: 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',
});
const isValid = ref(false);
const seasons = ref(new Array());
const dialog = ref(false);
const new_season_name = ref('');
const selectedDate = ref(new Date());
const date_dialog = ref(false);
const loading = ref(true);
const endLoading = ref(false);
const restartLoading = ref(false);
const startLoading = ref(false);
const cardtitle = ref(null);
const cardtext = ref(null);
const dialog1 = ref(false);
function info(title, text) {
cardtitle.value = title;
cardtext.value = text;
dialog1.value = true;
}
function formatDate(date) {
var d = new Date(date),
month = '0' + (d.getMonth() + 1),
day = '' + d.getDate(),
year = d.getFullYear();
return [year + '/' + month + '/' + day].join(''); // 返回形如 MM/DD 的字符串
}
function refresh() {
loading.value = true;
axios.get('/api/seasonInfo')
.then(function (response) {
const data = response.data;
seasons.value.length = 0;
for (var i = 0; i < data.Seasons.length; i++) {
const season = ref({
season_id: data.Seasons[i].season_id,
season_name: data.Seasons[i].season_name,
start_date: data.Seasons[i].start_date,
end_date: data.Seasons[i].end_date,
season_enable: data.Seasons[i].season_enable,
// user_is_su: data.Seasons[i].is_su,
})
seasons.value[i] = season;
}
})
.catch(function (error) {
console.log(error);
})
loading.value = false;
}
refresh();
function season_end(endSeason) {
endLoading.value = true;
axios.post('/api/seasonManage', {
season_id: endSeason.season_id,
condition_singal: 1,
})
.then(function (response) {
const data1 = response.data;
if (data1.status === "FAILED") {
info("结束失败!", "");
}
refresh();
})
.catch(function (error) {
console.log(error);
})
endLoading.value = false;
}
function season_restart(restartSeason) {
restartLoading.value = true;
axios.post('/api/seasonManage', {
season_id: restartSeason.season_id,
condition_singal: -1,
})
.then(function (response) {
const data1 = response.data;
if (data1.status === "FAILED") {
info("重启失败!", "");
}
refresh();
})
.catch(function (error) {
console.log(error);
})
restartLoading.value = false;
}
function season_start() {
startLoading.value = true;
axios.post('/api/seasonManage', {
season_name: new_season_name.value,
start_date: selectedDate.value.toLocaleDateString(),
condition_singal: 0,
})
.then(function (response) {
const data1 = response.data;
if (data1.status === "FAILED") {
info("开启失败!", "");
}
refresh();
dialog.value = false;
})
.catch(function (error) {
console.log(error);
})
startLoading.value = false;
}
</script>
\ No newline at end of file
......@@ -30,6 +30,7 @@ function testclick() {
-->
<script setup>
import Space from './components/space.vue';
// import { ref } from 'vue';
// const tab = ref(null)
// const text = ref('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.')
......@@ -43,20 +44,10 @@ function testclick() {
// }
</script>
<template>
<!-- <div>个人空间</div> -->
<Space></Space>
</template>
<style>
.main-card{
height: 100%;
width: 100%;
}
.tabs{
width: 100%;
position: fixed;
bottom: 0;
}
</style>
\ No newline at end of file
......@@ -8,7 +8,7 @@
import { registerPlugins } from '@/plugins'
// Components
import App from './gamemanage.vue'
import App from './user_audit.vue'
// Composables
import { createApp } from 'vue'
......
<template>
<v-app>
<v-data-table :loading="loading"item-value="return-object" return-object="true" v-model="selected" show-select :headers="headers"
:items="users" item-key="id" :search="search" :items-per-page="5">
<template v-slot:top>
<v-toolbar flat>
<v-toolbar-title>用户审核</v-toolbar-title>
<v-divider class="mx-3" inset vertical></v-divider>
<v-spacer></v-spacer>
<v-text-field v-model="search" append-icon="mdi-magnify" label="搜索" single-line
hide-details></v-text-field>
</v-toolbar>
</template>
<template v-slot:item.username="{ item }">
<p v-if="item.username" style="width:50px">{{ item.username }}</p>
</template>
<template v-slot:item.realname="{ item }">
<p v-if="item.realname" style="width:50px">{{ item.realname }}</p>
</template>
</v-data-table>
<div><v-btn style="width: 100px;" class="float-right" variant="text" color="indigo"
prepend-icon="mdi-check-circle" :loading="memberLoading" @click="setMember" text="审核通过"></v-btn></div>
</v-app>
<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>
</template>
<script setup>
import { ref } from 'vue';
import { reactive } from 'vue';
// import { computed } from 'vue';
import axios from 'axios';
const search = ref('');
// const actions_text = ref('');
const headers = reactive([
{ title: '用户名', key: 'username' },
{ title: '姓名', key: 'realname' },
// { title: '审核', key: 'actions' },
]);
const users = ref(new Array());
const selected = ref([]);
const loading = ref(true);
const memberLoading = ref(false);
const cardtitle = ref(null);
const cardtext = ref(null);
const dialog = ref(false);
function info(title, text) {
cardtitle.value = title;
cardtext.value = text;
dialog.value = true;
}
function refresh(){
loading.value = true;
axios.get('/api/getUser')
.then(function (response) {
const data = response.data;
users.value.length = 0;
// users.splice()
for (var i = 0; i < data.Unauidted_users.length; i++) {
const user = ref({
usr_id: data.Unauidted_users[i].user_id,
username: data.Unauidted_users[i].username,
realname: data.Unauidted_users[i].real_name,
is_member: false,
})
users.value[i] = user;
}
})
.catch(function (error) {
console.log(error);
})
loading.value = false;
}
refresh();
function setMember() {
memberLoading.value = true;
for (var j =0; j < selected.value.length; j++){
selected.value[j].is_member = true;
}
axios.post('/api/setMembers', selected.value)
.then(function(response) {
const data1 =response.data;
if (data1.status === "SUCCESS"){
info("审核成功!");
}
if (data1.status === "FAILED"){
info("未审核用户!");
}
refresh();
})
// .then(refresh())
.catch(function(error){
console.log(error);
})
memberLoading.value = false;
}
</script>
\ No newline at end of file
/**
* main.js
*
* Bootstraps Vuetify and other plugins then mounts the App`
*/
// Plugins
import { registerPlugins } from '@/plugins'
// Components
import App from './user_manage.vue'
// Composables
import { createApp } from 'vue'
const app = createApp(App)
registerPlugins(app)
app.mount('#app')
<template>
<v-app>
<v-data-table :loading="loading" :headers="headers" :items="users" item-key="id" :search="search" :items-per-page="5">
<template v-slot:top>
<v-toolbar flat>
<v-toolbar-title>用户管理</v-toolbar-title>
<v-divider class="mx-3" inset vertical></v-divider>
<v-spacer></v-spacer>
<v-text-field v-model="search" append-icon="mdi-magnify" label="搜索" single-line
hide-details></v-text-field>
</v-toolbar>
</template>
<template v-slot:item.userid="{ item }">
<p v-if="item.user_id" style="width:50px">{{ item.user_id }}</p>
</template>
<template v-slot:item.username="{ item }">
<p v-if="item.user_name" style="width:50px">{{ item.user_name }}</p>
</template>
<template v-slot:item.realname="{ item }">
<p v-if="item.user_realname" style="width:50px">{{ item.user_realname }}</p>
</template>
<template v-slot:item.password="{ item }">
<p v-if="item.user_password" style="width:50px">{{ item.user_password }}</p>
</template>
<template v-slot:item.is_member="{ item }">
<p v-if="item.user_is_member" style="width:50px">{{ item.user_is_member }}</p>
</template>
<template v-slot:item.is_su="{ item }">
<p v-if="item.user_is_su" style="width:50px">{{ item.user_is_su }}</p>
</template>
<template v-slot:item.actions="{ item }">
<v-icon @click="editUser(item)" style="width:50px">mdi-pencil</v-icon>
</template>
</v-data-table>
</v-app>
<v-dialog v-model="dialog" width="auto">
<v-card width="300px">
<v-card-title>
编辑用户信息
</v-card-title>
<v-card-text>
<v-form v-model="isValid">
<v-text-field v-model="selectUser.user_name" :rules="[rules.usrname]" variant="filled"
color="indigo" label="用户名"></v-text-field>
<v-text-field v-model="selectUser.user_realname" :rules="[rules.usrname]" variant="filled"
color="indigo" label="姓名"></v-text-field>
<v-text-field v-model="selectUser.user_password" :rules="[rules.password]" variant="filled"
color="indigo" label="密码"></v-text-field>
<v-select v-model="selectUser.is_member" :rules="[rules.su]" :items="['是', '否']"
variant="filled" color="indigo" label="会员"></v-select>
<v-select v-model="selectUser.is_su" :rules="[rules.member]" :items="['是', '否']"
variant="filled" color="indigo" label="管理员"></v-select>
</v-form>
</v-card-text>
<template v-slot:actions>
<v-btn :disabled="!isValid" :loading="userLoading" class="ms-auto" variant="flat" color="indigo" text="修改" @click="changeUser"></v-btn>
</template>
</v-card>
</v-dialog>
<v-dialog v-model="dialog1" 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>
</template>
<script setup>
import { ref } from 'vue';
import { reactive } from 'vue';
// import { computed } from 'vue';
import axios from 'axios';
const search = ref('');
// const actions_text = ref('');
const headers = reactive([
{ title: 'ID', key: 'userid' },
{ title: '用户名', key: 'username' },
{ title: '姓名', key: 'realname' },
{ title: '密码', key: 'password' },
{ title: '会员', key: 'is_member' },
{ title: '管理员', key: 'is_su' },
{ title: '编辑', key: 'actions' },
]);
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 || '用户名不能为空',
realname: v => !!v || '姓名不能为空',
confirmpassword: v => v === password.value || '密码不匹配',
password: v => !!v || '密码不能为空',
su: v => !!v || '管理员不能为空',
member: 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',
});
const isValid = ref(false);
const loading = ref(true);
const userLoading = ref(false);
const users = ref(new Array());
const dialog = ref(false);
const selectUser = ref({
user_id: 0,
user_name: '',
user_realname: '',
user_password: '',
user_is_member: false,
user_is_su: false,
is_member: '',
is_su: '',
});
const cardtitle = ref(null);
const cardtext = ref(null);
const dialog1 = ref(false);
function info(title, text) {
cardtitle.value = title;
cardtext.value = text;
dialog1.value = true;
}
function refresh() {
loading.value = true;
axios.get('/api/getUser')
.then(function (response) {
const data = response.data;
users.value.length = 0;
for (var i = 0; i < data.Users.length; i++) {
const user = ref({
user_id: data.Users[i].user_id,
user_name: data.Users[i].username,
user_realname: data.Users[i].real_name,
user_password: data.Users[i].password,
user_is_member: data.Users[i].is_member,
user_is_su: data.Users[i].is_su,
is_member: '',
is_su: '',
})
if (user.value.user_is_member){
user.value.is_member = '是'
}
if (!user.value.user_is_member){
user.value.is_member = '否'
}
if (user.value.user_is_su){
user.value.is_su = '是'
}
if (!user.value.user_is_su){
user.value.is_su = '否'
}
users.value[i] = user;
}
})
.catch(function (error) {
console.log(error);
})
loading.value = false;
}
refresh();
function editUser(item) {
dialog.value = true;
selectUser.value = item;
}
function changeUser() {
userLoading.value = true;
if (selectUser.value.is_member === '是'){
selectUser.value.user_is_member = true
}
if (selectUser.value.is_member === '否'){
selectUser.value.user_is_member = false
}
if (selectUser.value.is_su === '是'){
selectUser.value.user_is_su = true
}
if (selectUser.value.is_su === '否'){
selectUser.value.user_is_su = false
}
axios.post('/api/userManage', selectUser.value)
.then(function (response) {
const data1 = response.data;
if (data1.status === "FAILED") {
info("修改失败!", "");
}
dialog.value = false;
refresh();
})
.catch(function (error) {
console.log(error);
})
userLoading.value = false;
}
</script>
\ No newline at end of file
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>用户审核</title>
<style>
html,body,#app{
height: 100%;
}
</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="src/user_audit.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>用户管理</title>
<style>
html,body,#app{
height: 100%;
}
</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="src/user_manage.js"></script>
</body>
</html>
......@@ -52,11 +52,21 @@ export default defineConfig({
rollupOptions: {
input: {
index: resolve(__dirname, 'index.html'),
home: resolve(__dirname, 'home.html'),
// home: resolve(__dirname, 'home.html'),
space: resolve(__dirname, 'space.html'),
main: resolve(__dirname, 'main.html'),
lauched_games: resolve(__dirname, 'lauched_games.html'),
audit_games: resolve(__dirname, 'audit_games.html'),
my_recentgames: resolve(__dirname, 'my_recentgames.html'),
score_ranking: resolve(__dirname, 'score_ranking.html'),
// manage: resolve(__dirname, 'manage.html'),
user_audit: resolve(__dirname, 'user_audit.html'),
user_manage: resolve(__dirname, 'user_manage.html'),
season_manage: resolve(__dirname, 'season_manage.html'),
player_audit: resolve(__dirname, 'player_audit.html'),
player_manage: resolve(__dirname, 'player_manage.html'),
game_manage: resolve(__dirname, 'game_manage.html'),
past_seasons: resolve(__dirname, 'past_seasons.html'),
}
},
},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment