Skip to content
This repository was archived by the owner on Feb 5, 2024. It is now read-only.
43 changes: 41 additions & 2 deletions src/components/contest/Contest.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@
<span class="is-size-5 has-text-weight-bold">
期間: {{formatDate(startAt)}} ~ {{formatDate(endAt)}}<br>
</span>
<span
v-if="isFlexibleContest && isEntered"
class="is-size-5 has-text-weight-bold"
>
あなたのコンテスト時間:
{{formatDate(flexibleCreatedAt)}} ~
{{formatDate(flexibleEndAt)}}<br>
</span>
<span class="is-size-7">
作成日時: {{formatDate(createdAt)}}<br>
最終更新: {{formatDate(updatedAt)}}
Expand All @@ -19,8 +27,15 @@
</div>
</div>
<div class="navbar-end">
<span v-if="canEnter && !isEntered && problems === null" class="navbar-item">
<button @click="enter" class="button is-large is-outlined">
<span
v-if="enterable"
class="navbar-item"
>
<button
@click="myEnter"
class="button is-large is-outlined"
:disabled="this.isFlexibleContest && this.countDownTimer !== 'Already started'"
>
コンテストに参加する
</button>
</span>
Expand Down Expand Up @@ -67,6 +82,10 @@
</article>
</div>
<div class="container">
<EnterConfirmationModal
:isActive="showConfirmationModal"
@close="showConfirmationModal = false"
/>
<ErrorNotification :error="error"/>
<template v-if="problems !== null">
<div class="columns is-mobile" v-if="problems.length !== 0">
Expand Down Expand Up @@ -187,6 +206,7 @@ import ErrorNotification from '@/components/common/ErrorNotification';
import Modal from '@/components/common/Modal';
import SubmitModal from '@/components/problem/SubmitModal';
import ResultModal from './result_modal/ResultModal';
import EnterConfirmationModal from './EnterConfirmationModal';

import Tag from './Tag';

Expand All @@ -198,6 +218,7 @@ export default {
showStandingsModal: false,
showResultListModal: false,
showSubmitModal: false,
showConfirmationModal: false,
activeTab: 0,
diff: 300000,
};
Expand All @@ -216,6 +237,8 @@ export default {
'participants',
'id',
'error',
'duration',
'flexibleCreatedAt',
]),
...mapState('koneko/timeDiff', [
'timeDiff',
Expand All @@ -224,7 +247,15 @@ export default {
'canEnter',
'isEntered',
'isWriter',
'isFlexibleContest',
'flexibleEndAt',
]),
enterable() {
return this.canEnter &&
!this.isEntered &&
this.problems === null
;
},
countDownTimer() {
if (this.diff < 0) return 'Already started';
const DD = `00${Math.floor(this.diff / 1000 / 60 / 60 / 24)}`.slice(-2);
Expand Down Expand Up @@ -284,6 +315,13 @@ export default {
await this.getResults();
this.showResultListModal = true;
},
myEnter() {
if (this.isFlexibleContest) {
this.showConfirmationModal = true;
} else {
this.enter();
}
},
num2alpha(num) {
return String.fromCharCode(97 + num);
},
Expand All @@ -308,6 +346,7 @@ export default {
Tag,
Modal,
Problem,
EnterConfirmationModal,
ErrorNotification,
SubmitModal,
ResultModal,
Expand Down
49 changes: 49 additions & 0 deletions src/components/contest/EnterConfirmationModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<template>
<Modal
:isActive="isActive"
title="参加確認"
@close="close"
>
<p>
参加するとすぐにコンテストが始まります。<br/>
コンテスト時間は、参加から{{Math.floor(duration / 60)}}分です
</p>
<div slot="footer">
<button class="button is-success" @click="myEnter">参加する</button>
<button class="button" @click="close">キャンセル</button>
</div>
</Modal>
</template>

<script>
import { mapActions, mapState } from 'vuex';
import Modal from '@/components/common/Modal';

export default {
props: [
'isActive',
],
computed: {
...mapState('koneko/contests', [
'duration',
'id',
]),
},
methods: {
...mapActions('koneko/contests', [
'enter',
'getContest',
]),
async myEnter() {
await this.enter();
this.$emit('close');
},
close() {
this.$emit('close');
},
},
components: {
Modal,
},
};
</script>
37 changes: 34 additions & 3 deletions src/store/modules/contests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export default {
requiredWatching: false,
isWaitingJudge: true,
error: null,
duration: null,
flexibleCreatedAt: null,
},
getters: {
isWriter({ writers }, _, rootState) {
Expand All @@ -30,6 +32,15 @@ export default {
canEnter(_, { isWriter, isEntered }) {
return !isEntered && !isWriter;
},
isFlexibleContest({ duration }) {
return !!duration;
},
flexibleEndAt({ flexibleCreatedAt, duration }) {
if (flexibleCreatedAt === null) return null;
const tmp = new Date(flexibleCreatedAt);
tmp.setSeconds(tmp.getSeconds() + duration);
return tmp;
},
},
mutations: {
setContestData(state, contestData) {
Expand All @@ -48,8 +59,9 @@ export default {
name: v.name, displayName: v.displayName, id: v.id,
}));
state.participants = contestData.participants.map(v => ({
name: v.name, displayName: v.displayName, id: v.id,
name: v.user.name, displayName: v.user.displayName, id: v.user.id,
}));
state.duration = contestData.duration ? contestData.duration / 1000000000 : null;
},
setStatusesWatcherFlag(state) {
state.statusesWatcherFlag = true;
Expand All @@ -73,23 +85,34 @@ export default {
});
state.isWaitingJudge = state.problems.some(({ status }) => status < 2 && status > -1);
},
setFlexibleCreatedAt(state, createdAt) {
state.flexibleCreatedAt = createdAt;
},
waitJudge(state) {
state.isWaitingJudge = true;
},
setParticipants(state, participants) {
state.participants = participants.map(v => ({
name: v.name, displayName: v.displayName, id: v.id,
name: v.user.name, displayName: v.user.displayName, id: v.user.id,
}));
},
setError(state, error) {
state.error = error;
},
},
actions: {
async getContest({ commit, rootState }, contestID) {
async getContest({ state, commit, rootState }, contestID) {
try {
const res = await api.getContest(rootState.koneko.sessionID, contestID);
commit('setContestData', res.data);
if (state.duration) {
for (let i = 0; i < res.data.participants.length; i += 1) {
if (rootState.koneko.user.id === res.data.participants[i].user.id) {
commit('setFlexibleCreatedAt', new Date(res.data.participants[i].createdAt));
break;
}
}
}
commit('setRequiredWatching', true);
} catch (e) {
commit('setError', e);
Expand Down Expand Up @@ -128,6 +151,14 @@ export default {
try {
const res = await api.enterContest(rootState.koneko.sessionID, state.id);
commit('setParticipants', res.data.participants);
if (state.duration) {
for (let i = 0; i < res.data.participants.length; i += 1) {
if (rootState.koneko.user.id === res.data.participants[i].user.id) {
commit('setFlexibleCreatedAt', new Date(res.data.participants[i].createdAt));
break;
}
}
}
} catch (e) {
commit('setError', e);
}
Expand Down