Commit c56babd6 authored by xiaoye's avatar xiaoye

fix

parent e8af23d3
......@@ -25,11 +25,14 @@
"@dcloudio/uni-quickapp-webview": "3.0.0-4040520250104002",
"@types/sql.js": "^1.4.9",
"axios": "^1.8.4",
"js-base64": "^3.7.7",
"jszip": "^3.10.1",
"mitt": "^3.0.1",
"sql.js": "^1.13.0",
"vite-plugin-vue-setup-extend": "^0.4.0",
"vue": "^3.4.21",
"vue-i18n": "^9.1.9"
"vue-i18n": "^9.1.9",
"ygopro-deck-encode": "^1.0.7"
},
"devDependencies": {
"@dcloudio/types": "^3.4.8",
......@@ -8196,6 +8199,11 @@
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.3.7.tgz",
"integrity": "sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ=="
},
"node_modules/js-base64": {
"version": "3.7.7",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz",
"integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw=="
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
......@@ -10328,6 +10336,11 @@
"dev": true,
"peer": true
},
"node_modules/sql.js": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/sql.js/-/sql.js-1.13.0.tgz",
"integrity": "sha512-RJbVP1HRDlUUXahJ7VMTcu9Rm1Nzw+EBpoPr94vnbD4LwR715F3CcxE2G2k45PewcaZ57pjetYa+LoSJLAASgA=="
},
"node_modules/stack-utils": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
......@@ -11596,6 +11609,11 @@
"engines": {
"node": ">=10"
}
},
"node_modules/ygopro-deck-encode": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/ygopro-deck-encode/-/ygopro-deck-encode-1.0.7.tgz",
"integrity": "sha512-SGlANLsPb9OOY+0ojlt6LtajnL/MFxMHs9sglYxICm6ju0D91M46J6CaxH0DfjmwYWmg5u3sk/TdCvU3MGSBVA=="
}
}
}
......@@ -83,12 +83,7 @@
import {Tabulator, User} from '../script/post.ts';
import Mycard from '../script/mycard.ts';
import emitter from '../script/emitter.ts'
import {
updateTournament ,
tournamentInfo,
tournamentReload,
createOff
} from '../script/const.ts'
import Const from '../script/const.ts'
let create = reactive({
name : '',
......@@ -139,7 +134,7 @@
collaborators: collaborators
})
) {
emitter.emit(createOff);
emitter.emit(Const.createOff);
create.clear();
}
},
......
......@@ -240,6 +240,7 @@
pageSize = 20
:total = 'search.result.total'
v-show = 'page.menu'
@change = 'search.on()'
>
</uni-pagination>
</transition>
......@@ -259,12 +260,7 @@
import ApiKey from '../script/apikey.ts';
import Mycard from '../script/mycard.ts';
import emitter from '../script/emitter.ts'
import {
updateTournament ,
tournamentInfo,
tournamentReload,
createOff
} from '../script/const.ts'
import Const from '../script/const.ts'
import PageTournament from './tournament.vue';
import Create from './drawer.vue';
......@@ -448,7 +444,7 @@
tournament.visibility.select = tournament.this.visibility;
const collaborators = tournament.collaborators.map(user => user.id);
emitter.emit(updateTournament, {
emitter.emit(Const.updateTournament, {
name: tournament.name,
description: tournament.description,
visibility: tournament.visibility.select,
......@@ -488,15 +484,8 @@
page.show.drawer();
if (page.tournament)
page.show.menu();
await search.on({
pageCount : 1,
id : 0,
creator : Mycard.id >= 0 ? Mycard.id : 0,
name : '',
rule : '',
visibility : '',
status : ''
} as TournamentFindObject);
search.mine();
await search.on();
}
};
......@@ -513,10 +502,10 @@
onBeforeMount(() : void => {
Uniapp.chkScreen(size.get);
document.addEventListener("click", page.show.clear);
emitter.on(tournamentInfo, page.show.drawer);
emitter.on(Const.tournamentInfo, page.show.drawer);
// @ts-ignore
emitter.on(tournamentReload, tournament.init);
emitter.on(createOff, creator.off);
emitter.on(Const.createOff, creator.off);
const url = window.location.pathname.match(/\/tournament\/([^\/]+)(?=\/|$)/);
if (url && !isNaN(parseInt(url[1]))) {
......@@ -534,10 +523,10 @@
onUnmounted(() => {
document.removeEventListener("click", page.show.clear);
emitter.off(tournamentInfo, page.show.drawer);
emitter.off(Const.tournamentInfo, page.show.drawer);
// @ts-ignore
emitter.off(tournamentReload, tournament.init);
emitter.off(createOff, creator.off);
emitter.off(Const.createOff, creator.off);
});
watch(() => { return search.date; }, () => {
......
......@@ -12,30 +12,38 @@
>
<uni-forms>
<view class = 'button_list' >
<view class = 'button click' @click = 'tournament.operatorChk(() => { emitter.emit(tournamentInfo); })'>
<view class = 'button click' @click = 'tournament.operatorChk(() => { emitter.emit(Const.tournamentInfo); })'>
<span>设置</span>
<uni-icons type = 'info'></uni-icons>
</view>
<view class = 'button' @click = 'tournament.operatorChk(page.reload)'>
<view class = 'button' @click = 'page.reload()'>
<span>刷新</span>
<uni-icons type = 'reload'></uni-icons>
</view>
<view class = 'button' @click = 'tournament.operatorChk(page.clear)'>
<view class = 'button' @click = 'page.copyUrl()'>
<span>分享</span>
<uni-icons type = 'redo'></uni-icons>
</view>
<view class = 'button' @click = 'page.clear()'>
<span>关闭</span>
<uni-icons type = 'close'></uni-icons>
</view>
</view>
<br>
<view class = 'button_list' >
<view class = 'button click' @click = 'tournament.on()'>
<view class = 'button click' @click = 'tournament.operatorChk(tournament.on)'>
<span>{{ tournament.status.text.get(tournament.this.status) }}</span>
<uni-icons type = 'circle-filled' :color = 'tournament.status.color.get(tournament.this.status)'></uni-icons>
</view>
<view class = 'button click' @click = 'tournament.reset()'>
<view class = 'button click' @click = 'tournament.operatorChk(tournament.reset)'>
<span>重置</span>
<uni-icons type = 'loop'></uni-icons>
</view>
<view class = 'button click' @click = 'tournament.del()'>
<view class = 'button click' @click = 'tournament.operatorChk(tournament.upload)'>
<span>上传</span>
<uni-icons type = 'cloud-upload'></uni-icons>
</view>
<view class = 'button click' @click = 'tournament.operatorChk(tournament.del)'>
<span>删除</span>
<uni-icons type = 'trash' color = 'red'></uni-icons>
</view>
......@@ -70,10 +78,18 @@
</template>
<template v-slot:footer>
<view id = 'footer'>
<view
class = 'button'
:style = "{ '--color' : 'gray' }"
v-show = '!i.quit'
@click = 'tournament.operatorChk(participant.upload, [i])'
>
<uni-icons type = 'upload'></uni-icons>
</view>
<view
class = 'button'
:style = "{ '--color' : 'red' }"
@click = 'participant.del(v)'
@click = 'tournament.operatorChk(participant.del, [v])'
v-show = '!i.quit'
>
<uni-icons type = 'trash' color = 'red'></uni-icons>
......@@ -95,7 +111,7 @@
<view
class = 'button'
:style = "{ '--color' : '#409eff' }"
@click = 'participant.add()'
@click = 'tournament.operatorChk(participant.add)'
>
<uni-icons type = 'personadd'></uni-icons>
</view>
......@@ -139,10 +155,9 @@
title = '暂无比赛'
>
</uni-list-item>
<view v-for = '(i, v) in match.array'>
<view
class = 'match'
v-for = '(i, v) in match.array'
:style = "{ '--top' : `${44 * (v - 1.5)}px` }"
v-show = "match.submit.page === i && (i.status == 'Running' || i.status == 'Finished')"
>
<view id = 'score'>
......@@ -167,7 +182,6 @@
<view class = 'button' @click = 'match.submit.on(v)'>{{ i.status == 'Running' ? '提交比分' : i.status == 'Finished' ? '重赛' : '' }}</view>
</view>
<uni-list-item
v-for = '(i, v) in match.array'
:clickable = true
@click = 'match.submit.show(v)'
id = 'matchList'
......@@ -227,6 +241,7 @@
</view>
</template>
</uni-list-item>
</view>
</uni-list>
</transition>
<uni-pagination
......@@ -244,19 +259,17 @@
</view>
</template>
<script setup lang = 'ts'>
import { ref, reactive, onMounted, onUnmounted, onBeforeMount, watch} from 'vue';
import {ref, reactive, onMounted, onUnmounted, onBeforeMount, watch} from 'vue';
import YGOProDeck from 'ygopro-deck-encode';
import emitter from '../script/emitter.ts'
import UniApp from '../script/uniapp.ts';
import {Tabulator, User} from '../script/post.ts';
import Tournament from '../script/tournament.ts';
import Participant from '../script/participant.ts';
import Match from '../script/match.ts';
import {
updateTournament ,
tournamentInfo,
tournamentReload
} from '../script/const.ts'
import Const from '../script/const.ts'
import Mycard from '../script/mycard.ts';
import { AllParticipant, AllMatch, TournamentCreateObject, MatchUpdateObject, TournamentAParticipant } from '../script/type.ts'
import {TournamentCreateObject, MatchUpdateObject, TournamentAParticipant, ParticipantUpdateObject} from '../script/type.ts'
let tournament = reactive({
this : undefined as undefined | Tournament,
......@@ -304,9 +317,14 @@
success : async (res : UniApp.ShowModalRes) : Promise<void> => {
if (!res.confirm) return;
// @ts-ignore
if (await Tabulator.Tournament.Reset(Mycard.token, tournament.this.id))
if (await Tabulator.Tournament.Reset(Mycard.token, tournament.this.id)) {
for (const i of participant.array) {
if (i.quit)
await Tabulator.Participant.Delete(Mycard.token, i.id)
}
page.reload();
}
}
});
},
del : () : void => {
......@@ -329,6 +347,14 @@
content : '请先登陆或联系比赛主办方',
showCancel : false
});
},
upload : async (i : Participant) : Promise<void> => {
const f = async (res : UniApp.ChooseFileSuccessCallbackResult) : Promise<void> => {
// @ts-ignore
if (await Tabulator.Participant.UpdateYdk(Mycard.token, tournament.this.id, res.tempFiles[0], i.name))
await participant.search();
};
await UniApp.selectFile(['.ydk', '.txt'], f);
}
});
......@@ -412,10 +438,8 @@
});
}
// @ts-ignore
if (tournament.this.status == 'Ready' ? await del() : await update()) {
await (new Promise(resolve => setTimeout(resolve, 200)));
page.reload();
}
if (tournament.this.status == 'Ready' ? await del() : await update())
await participant.search();
},
update : async (Data : TournamentCreateObject) : Promise<void> => {
// @ts-ignore
......@@ -430,13 +454,26 @@
const t : TournamentAParticipant = await Tabulator.Tournament.Find(Mycard.token, id);
if (t.tournament) {
tournament.this = t.tournament;
emitter.emit(tournamentReload, tournament.this)
emitter.emit(Const.tournamentReload, tournament.this)
const participants = t.participant;
participant.array = participants.participants;
participant.total = participants.total;
return true;
}
return false;
},
upload : async (i : Participant) : Promise<void> => {
const f = async (res : UniApp.ChooseFileSuccessCallbackResult) : Promise<void> => {
if (res.tempFiles[0].size < Const.maxSize) {
i.updateDeck(await UniApp.readFile(res.tempFiles[0]));
if (await Tabulator.Participant.Update(Mycard.token, i.id, {
name : i.name,
deckbuf : i.deckbuf
} as ParticipantUpdateObject))
await participant.search();
}
};
await UniApp.selectFile(['.ydk', '.txt'], f, 1);
}
});
......@@ -484,6 +521,16 @@
}
match.submit.page = undefined;
match.submit.chk = match.array.map(i => [i.player1Score ?? 0, i.player2Score ?? 0]);
},
copyUrl : () => {
uni.setClipboardData({
data : `${window.location.href.split('/?')[0]}`,
success : () => {
uni.showToast({
title : '复制成功'
})
}
})
}
});
......@@ -507,7 +554,7 @@
await match.search();
});
watch(() => { return match.array; }, () => {
watch(() => { return match.array; }, async () : Promise<void> => {
match.submit.chk = match.array.map(i => [i.player1Score ?? 0, i.player2Score ?? 0]);
match.maxRound = match.array.find(i => i.isThirdPlaceMatch)?.round ?? match.round + 1;
}, {deep : true});
......
const updateTournament = 'updateTournament';
class ConstData {
maxSize = 1024 * 10;
updateTournament = 'updateTournament';
tournamentInfo = 'tournamentInfo';
tournamentReload = 'tournamentReload';
createOff = 'createOff';
}
const tournamentInfo = 'tournamentInfo';
const tournamentReload = 'tournamentReload';
const Const = new ConstData();
const createOff = 'createOff';
export {
updateTournament ,
tournamentInfo,
tournamentReload,
createOff
};
\ No newline at end of file
export default Const;
\ No newline at end of file
import { Score, ParticipantObject } from './type.ts';
import { Score, ParticipantObject, Deck } from './type.ts';
import YGOProDeck from 'ygopro-deck-encode';
import { Base64 } from 'js-base64';
class Participant {
id : number;
......@@ -7,6 +9,7 @@ class Participant {
tournamentId : number;
score : Score;
deckbuf : string;
deck : YGOProDeck | undefined;
constructor(obj: ParticipantObject) {
this.name = obj.name;
......@@ -15,6 +18,22 @@ class Participant {
this.score = obj.score;
this.deckbuf = obj.deckbuf ?? '';
this.quit = obj.quit ?? false;
if (obj.deckbuf)
this.deck = YGOProDeck.fromUpdateDeckPayload(Base64.toUint8Array(this.deckbuf));
}
updateDeck = (ydk : string) : void => {
this.deck = YGOProDeck.fromYdkString(ydk);
this.deckbuf = Base64.fromUint8Array(this.deck.toUpdateDeckPayload());
this.deck.main = [...this.deck.main, ...this.deck.extra]
}
getDeck = () : Deck => {
return {
main : this.deck?.main ?? [],
extra : this.deck?.extra ?? [],
side : this.deck?.side ?? [],
};
}
}
......
......@@ -23,6 +23,7 @@ import {
UserObject,
TournamentAParticipant
} from './type.ts'
import UniApp from './uniapp.ts';
class TabulatorAPI {
url : AxiosInstance;
......@@ -129,7 +130,7 @@ class TabulatorAPI {
recordsPerPage : 20,
pageCount : obj.pageCount ?? 1,
id : (obj.id ?? 0) > 0 ? obj.id : undefined,
creator : filter(obj.creator),
managing : filter(obj.creator),
name : filter(obj.name),
rule : filter(obj.rule),
visibility : filter(obj.visibility),
......@@ -234,6 +235,28 @@ class TabulatorAPI {
return false;
}
},
UpdateYdk : async (token : string, id : number, res : UniApp.ChooseFileSuccessCallbackResult) : Promise<Boolean> => {
let response : {
data : string
};
try {
// @ts-ignore
const files : Array<UniApp.UploadFileOptionFiles> = res.tempFiles.map(file => ({
name: 'files',
uri: file.path,
type: file.type
}));
response = await UniApp.uploadFile(
`${this.url.defaults.baseURL}/api/tournament/${id}/upload-ydk`, files, { 'x-user-token' : token }
)
const data = JSON.parse(response.data)
return data.success;
}
catch(error) {
console.error(error);
return false;
}
}
}
Participant = {
Create : async (token : string, Data : ParticipantCreateObject, Array : Array<Participant> = []) : Promise<boolean> => {
......@@ -613,7 +636,6 @@ class Users {
}
}
}
}
const User = new Users('https://sapi.moecube.com:444/accounts')
......
......@@ -158,6 +158,12 @@ interface UserObject {
username : string
}
interface Deck {
main : Array<number>;
extra : Array<number>;
side : Array<number>;
}
export {
Score,
TournamentObject,
......@@ -178,5 +184,6 @@ export {
AllMatch,
ruleSettings,
UserObject,
TournamentAParticipant
TournamentAParticipant,
Deck
}
\ No newline at end of file
class UniappFuncs {
async selectFile (f : Function) : Promise<any> {
selectFile (type : Array<string>, f : Function, count : number = 100) : any {
let result;
try {
// @ts-ignore
uni.chooseFile({
extension : ['.cdb'],
// @ts-ignore
extension : type,
count: count,
success : async (res : UniApp.ChooseFileSuccessCallbackResult) => { result = await f(res); }
});
} catch (err) {
......@@ -15,6 +15,36 @@ class UniappFuncs {
}
}
async uploadFile (url : string, files : Array<UniApp.UploadFileOptionFiles>, header : object) : Promise<any> {
return uni.uploadFile({
url : url,
files : files,
header : header,
});
}
async readFile (file) : Promise<string> {
if (typeof window !== 'undefined' && window.FileReader) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
// @ts-ignore
reader.onload = (e) => resolve(e.target.result as string);
reader.onerror = reject;
reader.readAsText(file);
});
} else {
return new Promise((resolve, reject) => {
// @ts-ignore
uni.readFile({
filePath: file.path,
encoding: 'utf-8',
success: (res) => resolve(res.data),
fail: reject
});
});
}
}
chkScreen (chk : Function) : void {
chk();
// #ifdef H5
......@@ -41,6 +71,6 @@ class UniappFuncs {
}
}
const Uniapp = new UniappFuncs()
const UniApp = new UniappFuncs()
export default Uniapp;
\ No newline at end of file
export default UniApp;
\ No newline at end of file
......@@ -24,7 +24,6 @@
}
#body {
position: relative;
width: 80%;
display: grid;
grid-template-columns: repeat(3, 1fr);
......@@ -59,6 +58,12 @@
}
}
#footer {
display: flex;
justify-content: center;
justify-items: center;
align-items: center;
column-gap: 10%;
width: 10%;
.button {
border: 0.5px solid var(--color);
width: auto;
......@@ -74,9 +79,7 @@
.match {
border: 1px solid gray;
position: absolute;
z-index: 1;
top : var(--top);
// left : 100%;
width: 100%;
background-color: white;
......
......@@ -48,3 +48,20 @@
transform: translateX(0%);
}
}
.move_up {
&-enter-active,
&-leave-active {
transition: transform 0.5s ease;
}
&-enter-from,
&-leave-to {
transform: translateY(-200%);
}
&-enter-to,
&-leave-from {
transform: translateY(0%);
}
}
\ No newline at end of file
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