feat: load session and display start button if not exists

This commit is contained in:
wancat committed 2024-06-27 11:55:34 +08:00
1 parent c64043316e
commit 3398d18055
7 files changed
+51 -56

No files matched your search

+16 -8
View File
@@ -1,14 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch } from 'vue' import { computed, ref, watch } from 'vue'
import useSession from '../../store/session' import useSession from '../../store/session'
import MarkdownText from '../MarkdownText.vue' import MarkdownText from '../MarkdownText.vue'
const sessionStore = useSession() const sessionStore = useSession()
const current = ref(-1) const current = ref(-1)
watch( watch(
() => sessionStore.session.hints, () => sessionStore.session?.hints,
(hints) => { (hints) => {
current.value = hints.length - 1 current.value = hints ? hints.length - 1 : -1
}, },
{ deep: true } { deep: true }
) )
@@ -20,10 +20,18 @@ const left = () => {
} }
const right = () => { const right = () => {
if (current.value < sessionStore.session.hints.length - 1) { if (current.value < (sessionStore.session?.hints.length ?? 0) - 1) {
current.value += 1 current.value += 1
} }
} }
const length = computed(() => {
return sessionStore.session?.hints.length ?? 0
})
const disabled = computed(() => {
return current.value === length.value - 1
})
</script> </script>
<template> <template>
@@ -50,13 +58,13 @@ const right = () => {
<p class="inline text-text font-xl w-1/14 p-2 m-1">{{ current + 1 }}</p> <p class="inline text-text font-xl w-1/14 p-2 m-1">{{ current + 1 }}</p>
<p class="inline text-text font-xl w-1/14 p-2 m-1">/</p> <p class="inline text-text font-xl w-1/14 p-2 m-1">/</p>
<p class="inline text-text font-xl w-1/14 p-2 m-1"> <p class="inline text-text font-xl w-1/14 p-2 m-1">
{{ sessionStore.session.hints.length }} {{ length }}
</p> </p>
<button <button
class="p-2 m-1 w-1/8" class="p-2 m-1 w-1/8"
id="Rbutton" id="Rbutton"
@click="right" @click="right"
:disabled="current === sessionStore.session.hints.length - 1" :disabled="disabled"
> >
<font-awesome-icon :icon="['fas', 'arrow-right']" class="text-text" /> <font-awesome-icon :icon="['fas', 'arrow-right']" class="text-text" />
</button> </button>
@@ -65,7 +73,7 @@ const right = () => {
<div id="hint" class="bg-bg p-8 overflow-y-auto"> <div id="hint" class="bg-bg p-8 overflow-y-auto">
<ul> <ul>
<li <li
v-for="response in sessionStore.session.responses[current]" v-for="response in sessionStore.session?.responses[current]"
:key="response.type" :key="response.type"
class="text-text font-xl whitespace-pre-wrap" class="text-text font-xl whitespace-pre-wrap"
> >
@@ -74,7 +82,7 @@ const right = () => {
</div> </div>
</li> </li>
<li <li
v-for="hint in sessionStore.session.hints[current]" v-for="hint in sessionStore.session?.hints[current]"
:key="hint" :key="hint"
class="text-text-primary font-xl whitespace-pre-wrap" class="text-text-primary font-xl whitespace-pre-wrap"
> >
+1 -1
View File
@@ -6,7 +6,7 @@ import { Task } from '../../types'
const sessionStore = useSession() const sessionStore = useSession()
const tasks = computed(() => { const tasks = computed(() => {
return sessionStore.session.tasks.map((task: Task) => { return sessionStore.session?.tasks.map((task: Task) => {
const prefix = task.completed ? '✓' : '➤' const prefix = task.completed ? '✓' : '➤'
const color = task.completed ? 'text-text-primary' : 'text-text' const color = task.completed ? 'text-text-primary' : 'text-text'
return { return {
+2 -17
View File
@@ -1,31 +1,16 @@
<script setup lang="ts"> <script setup lang="ts">
import { useToast } from 'vue-toastification' import { useToast } from 'vue-toastification'
import { onMounted, ref } from 'vue' import { computed } from 'vue'
import useSession from '../../store/session' import useSession from '../../store/session'
const props = defineProps({
questId: {
type: String,
required: true,
},
})
const toast = useToast() const toast = useToast()
const showCover = ref(true)
const sessionStore = useSession() const sessionStore = useSession()
onMounted(async () => { const showCover = computed(() => sessionStore.session === null)
sessionStore.setQuest(props.questId)
if (await sessionStore.getActiveSession()) {
showCover.value = false
}
sessionStore.setup()
})
const startSession = async () => { const startSession = async () => {
try { try {
await sessionStore.createSession() await sessionStore.createSession()
showCover.value = false
} catch (err: any) { } catch (err: any) {
console.error(err) console.error(err)
toast.error(err.message) toast.error(err.message)
+1
View File
@@ -10,6 +10,7 @@ const sessionStore = useSession()
<ul> <ul>
<li> <li>
<FileNode <FileNode
v-if="sessionStore.session"
:node="sessionStore.session.graph" :node="sessionStore.session.graph"
:pwd="sessionStore.session.pwd" :pwd="sessionStore.session.pwd"
/> />
+12 -25
View File
@@ -1,7 +1,7 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { FileGraph, FileObject } from '@linux-odyssey/file-graph' import { FileGraph, FileObject } from '@linux-odyssey/file-graph'
import { IQuest } from '@linux-odyssey/models' import { IQuest } from '@linux-odyssey/models'
import { createSession, getQuest, getSessions } from '../utils/api' import { createSession, getActiveSession, getQuest } from '../utils/api'
import Socket from '../utils/socket' import Socket from '../utils/socket'
import SocketTerminal from '../utils/terminal' import SocketTerminal from '../utils/terminal'
import { Session, StageResponse } from '../types' import { Session, StageResponse } from '../types'
@@ -10,26 +10,14 @@ const socket = new Socket()
const term = new SocketTerminal(40, 80) const term = new SocketTerminal(40, 80)
interface Store { interface Store {
session: Session session: Session | null
questId: string questId: string
quest: IQuest | null quest: IQuest | null
} }
const useSession = defineStore('session', { const useSession = defineStore('session', {
state: (): Store => ({ state: (): Store => ({
session: { session: null,
_id: '',
status: 'inactive',
graph: new FileGraph({
path: '/',
type: 'folder',
discovered: false,
}),
pwd: '',
hints: [],
tasks: [],
responses: [],
},
questId: '', questId: '',
quest: null, quest: null,
}), }),
@@ -50,19 +38,13 @@ const useSession = defineStore('session', {
this.setSession(session) this.setSession(session)
}, },
async getActiveSession() { async getActiveSession() {
const sessions = await getSessions({ const session = await getActiveSession(this.questId)
questId: this.questId, if (session) {
limit: 1, this.setSession(session)
order: 'desc',
status: 'active',
})
if (sessions.length > 0) {
this.setSession(sessions[0])
return true
} }
return false
}, },
updateGraph(event: { discover?: FileObject[]; pwd?: string }) { updateGraph(event: { discover?: FileObject[]; pwd?: string }) {
if (!this.session) return
if (event.discover) { if (event.discover) {
this.session.graph.discover(event.discover) this.session.graph.discover(event.discover)
} }
@@ -71,6 +53,7 @@ const useSession = defineStore('session', {
} }
}, },
newResponse(response: StageResponse) { newResponse(response: StageResponse) {
if (!this.session) return
this.session.responses.push(response.responses) this.session.responses.push(response.responses)
this.session.hints.push(response.hints) this.session.hints.push(response.hints)
this.session.tasks = response.tasks this.session.tasks = response.tasks
@@ -95,6 +78,10 @@ const useSession = defineStore('session', {
this.newResponse(response) this.newResponse(response)
}) })
}, },
setStatus(status: string) {
if (!this.session) return
this.session.status = status
},
}, },
}) })
+9
View File
@@ -34,3 +34,12 @@ export async function getSessions(
const res = await api.get<Session[]>('/sessions', { params: request }) const res = await api.get<Session[]>('/sessions', { params: request })
return res.data return res.data
} }
export async function getActiveSession(
questId: string
): Promise<Session | null> {
const res = await api.get<Session | null>('/sessions/active', {
params: { questId },
})
return res.data
}
+10 -5
View File
@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue' import { computed, onMounted } from 'vue'
// import { onMounted } from 'vue' // import { onMounted } from 'vue'
// import { useToast } from 'vue-toastification' // import { useToast } from 'vue-toastification'
import useSession from '../store/session' import useSession from '../store/session'
@@ -18,16 +18,21 @@ import StartButton from '../components/game/StartButton.vue'
const sessionStore = useSession() const sessionStore = useSession()
const completed = computed(() => { const completed = computed(() => {
return sessionStore.session.status === 'finished' return sessionStore.session?.status === 'finished'
}) })
defineProps({ const props = defineProps({
questId: { questId: {
type: String, type: String,
required: true, required: true,
}, },
}) })
// const toast = useToast()
onMounted(async () => {
sessionStore.setup()
await sessionStore.setQuest(props.questId)
await sessionStore.getActiveSession()
})
</script> </script>
<template> <template>
@@ -42,7 +47,7 @@ defineProps({
<input <input
type="hidden" type="hidden"
id="currentStatus" id="currentStatus"
:value="sessionStore.session.status" :value="sessionStore.session?.status"
/> />
<!-- main --> <!-- main -->
<div id="main" class="h-full pt-10 w-full flex p-3 space-x-3"> <div id="main" class="h-full pt-10 w-full flex p-3 space-x-3">