xiongzhu 2 yıl önce
ebeveyn
işleme
36f673485c
3 değiştirilmiş dosya ile 126 ekleme ve 20 silme
  1. 4 3
      src/enums/index.js
  2. 77 7
      src/views/GameView.vue
  3. 45 10
      src/views/PlayView.vue

+ 4 - 3
src/enums/index.js

@@ -27,9 +27,10 @@ export const UserRole = {
 }
 
 export const GameStatus = {
-    WAITING: '等待中',
-    PLAYING: '游戏中',
-    FINISH: '已完成'
+    created: '未初始化',
+    initialized: '已初始化',
+    running: '运行中',
+    finished: '已结束'
 }
 export const StreamPlatform = {
     twitch: 'Twitch',

+ 77 - 7
src/views/GameView.vue

@@ -5,12 +5,18 @@
         </template>
         <ElTableColumn prop="id" label="#" width="80" />
         <ElTableColumn prop="name" label="名称" min-width="120" />
-        <ElTableColumn prop="status" label="状态" :formatter="statusFormatter" width="120" />
+        <ElTableColumn prop="status" label="状态" width="150" :formatter="statusFormatter" />
+        <ElTableColumn prop="running" label="运行">
+            <template #default="{ row }">
+                <ElSwitch :model-value="row.status === 'running'" @update:model-value="onActiveChange($event, row)" />
+            </template>
+        </ElTableColumn>
         <ElTableColumn prop="createdAt" label="创建时间" :formatter="timeFormatter" width="150" />
         <ElTableColumn label="操作" align="center" width="350">
             <template #default="{ row }">
-                <ElButton @click="onPlay(row)" type="primary">进入</ElButton>
-                <ElButton @click="onEdit(row)">编辑</ElButton>
+                <ElButton v-if="row.status === 'created'" @click="onEdit(row)" type="primary">编辑</ElButton>
+                <ElButton v-if="row.status === 'created'" @click="onInit(row)" type="primary">初始化</ElButton>
+                <ElButton v-if="row.status !== 'created'" @click="onPlay(row)" type="primary">详情</ElButton>
                 <ElButton @click="onDelete(row)" type="danger">删除</ElButton>
             </template>
         </ElTableColumn>
@@ -61,6 +67,27 @@
             <ElButton @click="onAddCharactor">添加</ElButton>
         </ElFormItem>
     </EditDialog>
+    <ElDialog title="初始化" v-model="showInitDialog">
+        <ElForm :model="initModel" :rules="initRules" ref="initForm" label-position="right" label-width="80">
+            <ElFormItem label="日期" prop="date">
+                <ElDatePicker v-model="initModel.date" />
+            </ElFormItem>
+            <ElFormItem label="时间" prop="time">
+                <ElSelect v-model="initModel.time">
+                    <ElOption label="上午" value="morning" />
+                    <ElOption label="下午" value="afternoon" />
+                    <ElOption label="晚上" value="evening" />
+                </ElSelect>
+            </ElFormItem>
+            <ElFormItem label="初始剧情" prop="plot">
+                <ElInput v-model="initModel.plot" type="textarea" placeholder="不填则自动生成" :rows="3" />
+            </ElFormItem>
+        </ElForm>
+        <template #footer>
+            <ElButton @click="showInitDialog = false">取消</ElButton>
+            <ElButton type="primary" @click="init">确定</ElButton>
+        </template>
+    </ElDialog>
 </template>
 <script setup>
 import { ref } from 'vue'
@@ -69,13 +96,11 @@ import { useEnumFormatter, useTimeFormatter } from '@/utils/formatter'
 import { Plus } from '@vicons/tabler'
 import EditDialog from '@/components/EditDialog.vue'
 import { setupEditDialog } from '@/utils/editDialog'
-import EnumSelect from '@/components/EnumSelect.vue'
-import { GameStatus } from '@/enums'
 import { http } from '@/plugins/http'
 import { ElMessage, ElMessageBox } from 'element-plus'
-import { useClipboard } from '@vueuse/core'
 import { useRouter } from 'vue-router'
-import { StreamPlatform } from '@/enums'
+import { ElLoading } from 'element-plus'
+import { GameStatus } from '@/enums'
 
 const router = useRouter()
 const where = ref({})
@@ -159,6 +184,51 @@ function onPlay(row) {
         }
     })
 }
+const showInitDialog = ref(false)
+const initForm = ref(null)
+const initModel = ref({})
+const selectedRow = ref(null)
+const initRules = {
+    date: [{ required: true, message: '请选择日期', trigger: 'blur' }],
+    time: [{ required: true, message: '请选择时间', trigger: 'blur' }]
+}
+async function onInit(row) {
+    selectedRow.value = row
+    initModel.value = {}
+    initForm.value?.clearValidate()
+    showInitDialog.value = true
+}
+async function init() {
+    await initForm.value.validate()
+    const loadingInstance = ElLoading.service({
+        fullscreen: true
+    })
+    try {
+        await http.post(`/game/${selectedRow.value.id}/init`, initModel.value)
+        ElMessage.success('初始化成功')
+        table.value.refresh()
+        showInitDialog.value = false
+    } catch (error) {
+        ElMessage.error(error.message)
+    }
+    loadingInstance.close()
+}
+async function onActiveChange(e, row) {
+    const loadingInstance = ElLoading.service({
+        fullscreen: true
+    })
+    try {
+        if (e) {
+            await http.post(`/game/${row.id}/startRun`)
+        } else {
+            await http.post(`/game/${row.id}/stopRun`)
+        }
+        table.value.refresh()
+    } catch (error) {
+        ElMessage.error(error.message)
+    }
+    loadingInstance.close()
+}
 </script>
 <style lang="less" scoped>
 .charactor-form {

+ 45 - 10
src/views/PlayView.vue

@@ -10,7 +10,7 @@
         >
             <ElCard>
                 <span class="whitespace-pre-wrap" v-html="item.plot"></span>
-                <template v-if="index === history.length - 1 && item.choices.length">
+                <template v-if="index === history.length - 1 && item.choices && item.choices.length">
                     <br /><br />
                     <el-radio-group v-model="choice" class="ml-4">
                         <el-radio
@@ -22,6 +22,18 @@
                         </el-radio>
                     </el-radio-group>
                 </template>
+                <template v-else-if="item.choices && item.choices.length">
+                    <br /><br />
+                    <el-radio-group :model-value="item.picked" disabled class="ml-4">
+                        <el-radio
+                            v-for="c in item.choices"
+                            :key="c"
+                            :label="c"
+                            class="w-full !h-auto !whitespace-normal mb-4"
+                        >
+                        </el-radio>
+                    </el-radio-group>
+                </template>
                 <template v-if="index === history.length - 1">
                     <br />
                 </template>
@@ -29,21 +41,20 @@
         </el-timeline-item>
     </el-timeline>
     <div class="text-center">
-        <ElButtonGroup v-if="game.status === 'PLAYING'">
+        <ElButtonGroup v-if="game.status === 'initialized'">
             <ElButton :loading="loading" @click="continueGame(false)">继续</ElButton>
             <ElButton :loading="loading" @click="onAddCharactor(false)">加入角色继续</ElButton>
             <ElButton :loading="loading" @click="continueGame(true)">生成选择</ElButton>
             <ElButton :loading="loading" @click="onAddCharactor(true)">加入角色生成选择</ElButton>
             <ElButton :loading="loading" @click="revert">回退</ElButton>
         </ElButtonGroup>
-        <ElButton v-else @click="start" :loading="loading">开始</ElButton>
     </div>
 
     <!-- </div> -->
 </template>
 <script setup>
 import { http } from '@/plugins/http'
-import { ref, computed } from 'vue'
+import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
 import { useRoute } from 'vue-router'
 import { format } from 'date-fns'
 import { zhCN } from 'date-fns/locale'
@@ -58,13 +69,33 @@ const needChoice = computed(() => {
 async function getData(params) {
     http.get(`/game/${route.params.id}`, { params }).then((res) => {
         game.value = res
-    }),
-        http.get(`/game/${route.params.id}/history`, { params }).then((res) => {
-            history.value = res
-        })
-    choice.value = ''
+    })
+    http.get(`/game/${route.params.id}/history`, { params }).then((res) => {
+        for (let i = 0; i < res.length; i++) {
+            if (res[i].choices && res[i].choices.length && res[i + 1] && res[i + 1].pickedChoice) {
+                if (res[i + 1] && res[i + 1].pickedChoice) {
+                    res[i].picked = res[i + 1].pickedChoice
+                }
+            }
+        }
+        if (
+            res[res.length - 1] &&
+            history.value[history.value.length - 1] &&
+            res[res.length - 1].id !== history.value[history.value.length - 1].id
+        ) {
+            ElMessage.success('有新的剧情')
+            choice.value = ''
+        }
+        history.value = res
+    })
 }
 getData()
+const timer = setInterval(() => {
+    getData()
+}, 2000)
+onBeforeUnmount(() => {
+    clearInterval(timer)
+})
 function formatDatetime(date, time) {
     return (
         format(new Date(date), 'MMMdo', { locale: zhCN }) +
@@ -105,7 +136,11 @@ async function continueGame(genChoice = false, addCharactor = null) {
 
 async function revert() {
     loading.value = true
-    await http.post(`/game/${route.params.id}/revert`)
+    try {
+        await http.post(`/game/${route.params.id}/revert`)
+    } catch (error) {
+        ElMessage.error(error.message)
+    }
     loading.value = false
     getData()
 }