|
@@ -1,52 +1,1183 @@
|
|
|
<template>
|
|
|
- <view class="play-room-page">
|
|
|
- <view class="title">游戏进行中</view>
|
|
|
- <nut-empty description="正在开发中..." image="empty" />
|
|
|
+ <view class="play-room-page">
|
|
|
+ <!-- 游戏头部信息 -->
|
|
|
+ <view class="game-header" :class="isHost ? 'host-header' : 'player-header'">
|
|
|
+ <view class="game-title">
|
|
|
+ {{ gameTitle }}
|
|
|
+ <view class="tag" :class="isHost ? 'host-tag' : 'player-tag'">
|
|
|
+ {{ isHost ? '主持人' : '玩家' }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="game-info">
|
|
|
+ <view class="timer">
|
|
|
+ <IconFont name="clock" size="16"></IconFont>
|
|
|
+ 已进行: {{ gameDuration }}分钟
|
|
|
+ </view>
|
|
|
+ <view class="status">{{ statusText }}</view>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
- <Tabbar></Tabbar>
|
|
|
- </template>
|
|
|
+
|
|
|
+ <!-- 游戏内容区域 -->
|
|
|
+ <view class="game-content">
|
|
|
+ <!-- 故事展示区 -->
|
|
|
+ <view class="scenario-card">
|
|
|
+ <view class="scenario-title">故事</view>
|
|
|
+ <view class="scenario-text">{{ currentView?.description || '故事加载中...' }}</view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 进度条 -->
|
|
|
+ <view class="progress-section">
|
|
|
+ <view class="progress-label">解谜进度: {{ gameProgress }}%</view>
|
|
|
+ <nut-progress
|
|
|
+ :percentage="gameProgress"
|
|
|
+ stroke-color="#3C92FB"
|
|
|
+ :text-inside="true"
|
|
|
+ stroke-width="14"
|
|
|
+ ></nut-progress>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 主持人视图 -->
|
|
|
+ <template v-if="isHost">
|
|
|
+ <view class="host-solution">
|
|
|
+ <view class="solution-title">真相(仅主持人可见)</view>
|
|
|
+ <view class="solution-text">{{ hostView?.solution || '真相加载中...' }}</view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="hints-manager">
|
|
|
+ <view class="hints-title">线索管理</view>
|
|
|
+ <view class="hints-list">
|
|
|
+ <view
|
|
|
+ v-for="hint in hostView?.hints"
|
|
|
+ :key="hint.id"
|
|
|
+ class="hint-item"
|
|
|
+ :class="{ 'revealed': hint.revealed }"
|
|
|
+ >
|
|
|
+ <view class="hint-content">{{ hint.content }}</view>
|
|
|
+ <nut-button
|
|
|
+ v-if="!hint.revealed"
|
|
|
+ size="small"
|
|
|
+ type="primary"
|
|
|
+ @click="revealHint(hint.id)"
|
|
|
+ >
|
|
|
+ 公开
|
|
|
+ </nut-button>
|
|
|
+ <view v-else class="revealed-time">
|
|
|
+ {{ formatTime(hint.revealedAt) }}已公开
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="pending-questions">
|
|
|
+ <view class="questions-title">待回答问题</view>
|
|
|
+ <view v-if="pendingQuestions.length === 0" class="no-questions">
|
|
|
+ 暂无待回答问题
|
|
|
+ </view>
|
|
|
+ <view v-else class="questions-list">
|
|
|
+ <view
|
|
|
+ v-for="question in pendingQuestions"
|
|
|
+ :key="question.id"
|
|
|
+ class="question-item"
|
|
|
+ >
|
|
|
+ <view class="question-header">
|
|
|
+ <view class="asker-name">{{ question.askedByName }}</view>
|
|
|
+ <view class="ask-time">{{ formatTime(question.timestamp) }}</view>
|
|
|
+ </view>
|
|
|
+ <view class="question-content">{{ question.content }}</view>
|
|
|
+ <view class="answer-buttons">
|
|
|
+ <nut-button
|
|
|
+ size="small"
|
|
|
+ type="success"
|
|
|
+ @click="answerQuestion(question.id, TurtleSoupAnswerType.YES)"
|
|
|
+ >
|
|
|
+ 是
|
|
|
+ </nut-button>
|
|
|
+ <nut-button
|
|
|
+ size="small"
|
|
|
+ type="danger"
|
|
|
+ @click="answerQuestion(question.id, TurtleSoupAnswerType.NO)"
|
|
|
+ >
|
|
|
+ 否
|
|
|
+ </nut-button>
|
|
|
+ <nut-button
|
|
|
+ size="small"
|
|
|
+ @click="answerQuestion(question.id, TurtleSoupAnswerType.IRRELEVANT)"
|
|
|
+ >
|
|
|
+ 不重要
|
|
|
+ </nut-button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="host-controls">
|
|
|
+ <nut-button
|
|
|
+ block
|
|
|
+ type="primary"
|
|
|
+ size="large"
|
|
|
+ @click="updateGameProgress"
|
|
|
+ >
|
|
|
+ 更新进度
|
|
|
+ </nut-button>
|
|
|
+ <nut-button
|
|
|
+ block
|
|
|
+ type="success"
|
|
|
+ size="large"
|
|
|
+ @click="showSolvedDialog = true"
|
|
|
+ >
|
|
|
+ 有人解出了!
|
|
|
+ </nut-button>
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <!-- 玩家视图 -->
|
|
|
+ <template v-else>
|
|
|
+ <view class="revealed-hints">
|
|
|
+ <view class="hints-title">已公开线索</view>
|
|
|
+ <view v-if="revealedHints.length === 0" class="no-hints">
|
|
|
+ 主持人尚未公开任何线索
|
|
|
+ </view>
|
|
|
+ <view v-else class="hints-list">
|
|
|
+ <view
|
|
|
+ v-for="hint in revealedHints"
|
|
|
+ :key="hint.id"
|
|
|
+ class="hint-item"
|
|
|
+ >
|
|
|
+ <view class="hint-content">{{ hint.content }}</view>
|
|
|
+ <view class="revealed-time">{{ formatTime(hint.revealedAt) }}</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="question-section">
|
|
|
+ <view class="question-title">我的提问</view>
|
|
|
+ <view class="question-input">
|
|
|
+ <nut-textarea
|
|
|
+ v-model="questionDraft"
|
|
|
+ placeholder="请输入您的问题,主持人会以是/否/不重要进行回答"
|
|
|
+ max-length="100"
|
|
|
+ ></nut-textarea>
|
|
|
+ <nut-button
|
|
|
+ block
|
|
|
+ type="primary"
|
|
|
+ size="large"
|
|
|
+ :disabled="!questionDraft.trim()"
|
|
|
+ @click="submitQuestion"
|
|
|
+ >
|
|
|
+ 提交问题
|
|
|
+ </nut-button>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="my-questions">
|
|
|
+ <view class="questions-subtitle">我的提问历史</view>
|
|
|
+ <view v-if="myQuestions.length === 0" class="no-questions">
|
|
|
+ 您还没有提出任何问题
|
|
|
+ </view>
|
|
|
+ <view v-else class="questions-list">
|
|
|
+ <view
|
|
|
+ v-for="question in myQuestions"
|
|
|
+ :key="question.id"
|
|
|
+ class="question-item"
|
|
|
+ >
|
|
|
+ <view class="question-header">
|
|
|
+ <view class="ask-time">{{ formatTime(question.timestamp) }}</view>
|
|
|
+ </view>
|
|
|
+ <view class="question-content">{{ question.content }}</view>
|
|
|
+ <view v-if="question.answered" class="question-answer" :class="getAnswerClass(question.answer)">
|
|
|
+ {{ formatAnswer(question.answer) }}
|
|
|
+ </view>
|
|
|
+ <view v-else class="question-pending">
|
|
|
+ 等待回答...
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="all-questions">
|
|
|
+ <view class="all-questions-title">所有问题</view>
|
|
|
+ <view v-if="sortedQuestions.length === 0" class="no-questions">
|
|
|
+ 暂无已回答问题
|
|
|
+ </view>
|
|
|
+ <view v-else class="questions-list">
|
|
|
+ <view
|
|
|
+ v-for="question in sortedQuestions"
|
|
|
+ :key="question.id"
|
|
|
+ class="question-item"
|
|
|
+ >
|
|
|
+ <view class="question-header">
|
|
|
+ <view class="asker-name">{{ question.askedByName }}</view>
|
|
|
+ <view class="ask-time">{{ formatTime(question.timestamp) }}</view>
|
|
|
+ </view>
|
|
|
+ <view class="question-content">{{ question.content }}</view>
|
|
|
+ <view class="question-answer" :class="getAnswerClass(question.answer)">
|
|
|
+ {{ formatAnswer(question.answer) }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="player-controls">
|
|
|
+ <nut-button
|
|
|
+ block
|
|
|
+ type="primary"
|
|
|
+ size="large"
|
|
|
+ @click="showSolutionDialog = true"
|
|
|
+ >
|
|
|
+ 提交解答
|
|
|
+ </nut-button>
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 弹窗区域 -->
|
|
|
+ <!-- 更新进度弹窗 -->
|
|
|
+ <nut-dialog
|
|
|
+ v-model:visible="showProgressDialog"
|
|
|
+ title="更新解谜进度"
|
|
|
+ content-align="center"
|
|
|
+ >
|
|
|
+ <view class="progress-dialog">
|
|
|
+ <view class="progress-label">当前进度: {{ progressValue }}%</view>
|
|
|
+ <nut-range
|
|
|
+ v-model="progressValue"
|
|
|
+ :min="0"
|
|
|
+ :max="100"
|
|
|
+ inactive-color="#E5E5E5"
|
|
|
+ button-color="#3C92FB"
|
|
|
+ active-color="#3C92FB"
|
|
|
+ ></nut-range>
|
|
|
+ <view class="dialog-buttons">
|
|
|
+ <nut-button type="primary" block @click="confirmProgress">确认</nut-button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </nut-dialog>
|
|
|
+
|
|
|
+ <!-- 提交解答弹窗 -->
|
|
|
+ <nut-dialog
|
|
|
+ v-model:visible="showSolutionDialog"
|
|
|
+ title="提交解答"
|
|
|
+ content-align="center"
|
|
|
+ >
|
|
|
+ <view class="solution-dialog">
|
|
|
+ <nut-textarea
|
|
|
+ v-model="solutionDraft"
|
|
|
+ placeholder="请输入你的解答"
|
|
|
+ max-length="300"
|
|
|
+ ></nut-textarea>
|
|
|
+ <view class="dialog-buttons">
|
|
|
+ <nut-button type="primary" block @click="submitSolution">提交</nut-button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </nut-dialog>
|
|
|
+
|
|
|
+ <!-- 解答正确弹窗 -->
|
|
|
+ <nut-dialog
|
|
|
+ v-model:visible="showSolvedDialog"
|
|
|
+ title="有人解出了谜题"
|
|
|
+ content-align="center"
|
|
|
+ >
|
|
|
+ <view class="solved-dialog">
|
|
|
+ <view class="solver-input">
|
|
|
+ <nut-input v-model="solverName" placeholder="解答者昵称" />
|
|
|
+ </view>
|
|
|
+ <nut-textarea
|
|
|
+ v-model="solverSolution"
|
|
|
+ placeholder="解答者的答案"
|
|
|
+ max-length="300"
|
|
|
+ ></nut-textarea>
|
|
|
+ <view class="dialog-buttons">
|
|
|
+ <nut-button type="primary" block @click="endGameWithSolvedStatus">确认</nut-button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </nut-dialog>
|
|
|
+ </view>
|
|
|
+ <Tabbar></Tabbar>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts">
|
|
|
+import Taro from '@tarojs/taro'
|
|
|
+import { ref, computed, onMounted, onUnmounted } from 'vue'
|
|
|
+import { useRoomStore } from '@/stores/room'
|
|
|
+import { useUserStore } from '@/stores/user'
|
|
|
+import { useTurtleSoupStore } from '@/stores/games/turtlesoup'
|
|
|
+import Tabbar from '@/components/Tabbar.vue'
|
|
|
+import { TurtleSoupAnswerType, TurtleSoupGameStatus } from '@/types/games/turtlesoup'
|
|
|
+import { IconFont } from '@nutui/icons-vue-taro'
|
|
|
+
|
|
|
+export default {
|
|
|
+ components: {
|
|
|
+ Tabbar,
|
|
|
+ IconFont
|
|
|
+ },
|
|
|
+
|
|
|
+ // 生命周期钩子 - 页面显示
|
|
|
+ onShow() {
|
|
|
+ // 隐藏返回首页按钮
|
|
|
+ Taro.hideHomeButton()
|
|
|
+ console.log('已隐藏返回首页按钮')
|
|
|
+ },
|
|
|
+
|
|
|
+ // Composition API
|
|
|
+ setup() {
|
|
|
+ // 初始化store
|
|
|
+ const roomStore = useRoomStore()
|
|
|
+ const userStore = useUserStore()
|
|
|
+ const turtleSoupStore = useTurtleSoupStore()
|
|
|
+
|
|
|
+ // 游戏和房间ID
|
|
|
+ const roomId = ref('')
|
|
|
+ const gameId = ref('')
|
|
|
+
|
|
|
+ // 问题输入
|
|
|
+ const questionDraft = ref('')
|
|
|
+
|
|
|
+ // 解答输入
|
|
|
+ const solutionDraft = ref('')
|
|
|
+
|
|
|
+ // 主持人提交解答者
|
|
|
+ const solverName = ref('')
|
|
|
+ const solverSolution = ref('')
|
|
|
+
|
|
|
+ // 进度值
|
|
|
+ const progressValue = ref(0)
|
|
|
+
|
|
|
+ // 弹窗控制
|
|
|
+ const showProgressDialog = ref(false)
|
|
|
+ const showSolutionDialog = ref(false)
|
|
|
+ const showSolvedDialog = ref(false)
|
|
|
+
|
|
|
+ // 从store获取视图数据
|
|
|
+ const currentView = computed(() => turtleSoupStore.currentView)
|
|
|
+ const hostView = computed(() => turtleSoupStore.hostView)
|
|
|
+ const playerView = computed(() => turtleSoupStore.playerView)
|
|
|
+ const isHost = computed(() => turtleSoupStore.isHost)
|
|
|
+ const isGameActive = computed(() => turtleSoupStore.isGameActive)
|
|
|
+ const gameProgress = computed(() => turtleSoupStore.gameProgress)
|
|
|
+ const gameDuration = computed(() => turtleSoupStore.gameDuration)
|
|
|
+ const pendingQuestions = computed(() => turtleSoupStore.pendingQuestions)
|
|
|
+ const myQuestions = computed(() => turtleSoupStore.myQuestions)
|
|
|
+ const revealedHints = computed(() => turtleSoupStore.revealedHints)
|
|
|
+ const sortedQuestions = computed(() => turtleSoupStore.sortedQuestions)
|
|
|
+
|
|
|
+ // 游戏标题
|
|
|
+ const gameTitle = computed(() => {
|
|
|
+ return currentView.value?.title || '海龟汤游戏'
|
|
|
+ })
|
|
|
+
|
|
|
+ // 状态文本
|
|
|
+ const statusText = computed(() => {
|
|
|
+ if (!currentView.value) return '游戏状态未知'
|
|
|
+
|
|
|
+ switch(currentView.value.status) {
|
|
|
+ case TurtleSoupGameStatus.CREATED:
|
|
|
+ return '等待开始'
|
|
|
+ case TurtleSoupGameStatus.WAITING:
|
|
|
+ return '准备中'
|
|
|
+ case TurtleSoupGameStatus.ACTIVE:
|
|
|
+ return '游戏进行中'
|
|
|
+ case TurtleSoupGameStatus.COMPLETED:
|
|
|
+ return '已完成'
|
|
|
+ case TurtleSoupGameStatus.ABANDONED:
|
|
|
+ return '已放弃'
|
|
|
+ default:
|
|
|
+ return '游戏状态未知'
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // 初始化页面
|
|
|
+ const initPage = async () => {
|
|
|
+ try {
|
|
|
+ // 获取路由参数
|
|
|
+ const pages = Taro.getCurrentPages()
|
|
|
+ const currentPage = pages[pages.length - 1]
|
|
|
+ const routeParams = currentPage.$taroParams
|
|
|
+
|
|
|
+ if (routeParams) {
|
|
|
+ if (routeParams.roomId) {
|
|
|
+ roomId.value = routeParams.roomId
|
|
|
+ }
|
|
|
+
|
|
|
+ if (routeParams.gameId) {
|
|
|
+ gameId.value = routeParams.gameId
|
|
|
+ } else if (roomId.value) {
|
|
|
+ // 如果没有gameId但有roomId,尝试从房间信息获取游戏ID
|
|
|
+ await roomStore.loadRoomInfo(roomId.value)
|
|
|
+ if (roomStore.currentRoom?.gameId) {
|
|
|
+ gameId.value = roomStore.currentRoom.gameId
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (gameId.value) {
|
|
|
+ // 判断当前用户角色并加载相应视图
|
|
|
+ const isCurrentUserHost = roomStore.getUserRole(userStore.openid) === 'hoster'
|
|
|
+ turtleSoupStore.setViewType(isCurrentUserHost ? 'host' : 'player')
|
|
|
+
|
|
|
+ await loadGameData()
|
|
|
+
|
|
|
+ // 更新进度值
|
|
|
+ progressValue.value = gameProgress.value
|
|
|
+
|
|
|
+ // 启动定时刷新
|
|
|
+ startGameListener()
|
|
|
+ } else {
|
|
|
+ Taro.showToast({
|
|
|
+ title: '游戏ID不存在',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ Taro.navigateBack()
|
|
|
+ }, 1500)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('初始化页面失败:', error)
|
|
|
+ Taro.showToast({
|
|
|
+ title: '加载游戏失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加载游戏数据
|
|
|
+ const loadGameData = async () => {
|
|
|
+ if (!gameId.value) return false
|
|
|
+
|
|
|
+ try {
|
|
|
+ Taro.showLoading({ title: '加载游戏数据...' })
|
|
|
+
|
|
|
+ let result
|
|
|
+ if (isHost.value) {
|
|
|
+ result = await turtleSoupStore.loadHostGame(gameId.value)
|
|
|
+ } else {
|
|
|
+ result = await turtleSoupStore.loadPlayerGame(gameId.value)
|
|
|
+ }
|
|
|
+
|
|
|
+ Taro.hideLoading()
|
|
|
+ return result
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载游戏数据失败:', error)
|
|
|
+ Taro.hideLoading()
|
|
|
+ Taro.showToast({
|
|
|
+ title: '加载游戏数据失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 提交问题 (玩家)
|
|
|
+ const submitQuestion = async () => {
|
|
|
+ if (!questionDraft.value.trim()) {
|
|
|
+ Taro.showToast({
|
|
|
+ title: '问题不能为空',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ Taro.showLoading({ title: '提交问题中...' })
|
|
|
+
|
|
|
+ const result = await turtleSoupStore.submitQuestion(questionDraft.value)
|
|
|
+
|
|
|
+ Taro.hideLoading()
|
|
|
+
|
|
|
+ if (result) {
|
|
|
+ Taro.showToast({
|
|
|
+ title: '问题已提交',
|
|
|
+ icon: 'success'
|
|
|
+ })
|
|
|
+ questionDraft.value = '' // 清空输入
|
|
|
+ } else {
|
|
|
+ Taro.showToast({
|
|
|
+ title: turtleSoupStore.error || '提交失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('提交问题失败:', error)
|
|
|
+ Taro.hideLoading()
|
|
|
+ Taro.showToast({
|
|
|
+ title: '提交问题失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 回答问题 (主持人)
|
|
|
+ const answerQuestion = async (questionId: string, answer: TurtleSoupAnswerType) => {
|
|
|
+ try {
|
|
|
+ Taro.showLoading({ title: '回答问题中...' })
|
|
|
+
|
|
|
+ const result = await turtleSoupStore.answerQuestion(questionId, answer)
|
|
|
+
|
|
|
+ Taro.hideLoading()
|
|
|
+
|
|
|
+ if (result) {
|
|
|
+ Taro.showToast({
|
|
|
+ title: '已回答',
|
|
|
+ icon: 'success'
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ Taro.showToast({
|
|
|
+ title: turtleSoupStore.error || '回答失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('回答问题失败:', error)
|
|
|
+ Taro.hideLoading()
|
|
|
+ Taro.showToast({
|
|
|
+ title: '回答问题失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 公开提示 (主持人)
|
|
|
+ const revealHint = async (hintId: string) => {
|
|
|
+ try {
|
|
|
+ Taro.showLoading({ title: '公开提示中...' })
|
|
|
+
|
|
|
+ const result = await turtleSoupStore.revealHint(hintId)
|
|
|
+
|
|
|
+ Taro.hideLoading()
|
|
|
+
|
|
|
+ if (result) {
|
|
|
+ Taro.showToast({
|
|
|
+ title: '提示已公开',
|
|
|
+ icon: 'success'
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ Taro.showToast({
|
|
|
+ title: turtleSoupStore.error || '公开提示失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('公开提示失败:', error)
|
|
|
+ Taro.hideLoading()
|
|
|
+ Taro.showToast({
|
|
|
+ title: '公开提示失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新游戏进度对话框
|
|
|
+ const updateGameProgress = () => {
|
|
|
+ // 确保进度值与当前存储进度一致
|
|
|
+ progressValue.value = gameProgress.value
|
|
|
+ showProgressDialog.value = true
|
|
|
+ }
|
|
|
+
|
|
|
+ // 确认更新进度 (主持人)
|
|
|
+ const confirmProgress = async () => {
|
|
|
+ try {
|
|
|
+ Taro.showLoading({ title: '更新进度中...' })
|
|
|
+
|
|
|
+ const result = await turtleSoupStore.updateProgress(progressValue.value)
|
|
|
+
|
|
|
+ Taro.hideLoading()
|
|
|
+
|
|
|
+ if (result) {
|
|
|
+ showProgressDialog.value = false
|
|
|
+ Taro.showToast({
|
|
|
+ title: '进度已更新',
|
|
|
+ icon: 'success'
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ Taro.showToast({
|
|
|
+ title: turtleSoupStore.error || '更新进度失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('更新进度失败:', error)
|
|
|
+ Taro.hideLoading()
|
|
|
+ Taro.showToast({
|
|
|
+ title: '更新进度失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 提交解答 (玩家)
|
|
|
+ const submitSolution = async () => {
|
|
|
+ if (!solutionDraft.value.trim()) {
|
|
|
+ Taro.showToast({
|
|
|
+ title: '解答不能为空',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ Taro.showLoading({ title: '提交解答中...' })
|
|
|
+
|
|
|
+ const result = await turtleSoupStore.submitSolution(solutionDraft.value)
|
|
|
+
|
|
|
+ Taro.hideLoading()
|
|
|
+ showSolutionDialog.value = false
|
|
|
+
|
|
|
+ if (result.success) {
|
|
|
+ if (result.correct) {
|
|
|
+ Taro.showModal({
|
|
|
+ title: '恭喜你!',
|
|
|
+ content: '你的解答正确!',
|
|
|
+ confirmText: '确定',
|
|
|
+ showCancel: false
|
|
|
+ })
|
|
|
+
|
|
|
+ // 主持人会处理游戏结束
|
|
|
+ solutionDraft.value = '' // 清空输入
|
|
|
+ } else {
|
|
|
+ Taro.showToast({
|
|
|
+ title: '解答不正确,再试试吧!',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ Taro.showToast({
|
|
|
+ title: turtleSoupStore.error || '提交解答失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('提交解答失败:', error)
|
|
|
+ Taro.hideLoading()
|
|
|
+ Taro.showToast({
|
|
|
+ title: '提交解答失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 结束游戏 (主持人提交解答者)
|
|
|
+ const endGameWithSolvedStatus = async () => {
|
|
|
+ if (!solverName.value.trim() || !solverSolution.value.trim()) {
|
|
|
+ Taro.showToast({
|
|
|
+ title: '请填写解答者和解答内容',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ Taro.showLoading({ title: '结束游戏中...' })
|
|
|
+
|
|
|
+ const result = await turtleSoupStore.endGame({
|
|
|
+ gameId: gameId.value,
|
|
|
+ solved: true,
|
|
|
+ solvedBy: 'player', // 实际应用中应该是玩家ID
|
|
|
+ solvedByName: solverName.value,
|
|
|
+ solution: solverSolution.value
|
|
|
+ })
|
|
|
+
|
|
|
+ Taro.hideLoading()
|
|
|
+ showSolvedDialog.value = false
|
|
|
+
|
|
|
+ if (result) {
|
|
|
+ Taro.showModal({
|
|
|
+ title: '游戏已结束',
|
|
|
+ content: `恭喜玩家 ${solverName.value} 成功解谜!`,
|
|
|
+ confirmText: '返回房间',
|
|
|
+ showCancel: false,
|
|
|
+ success: () => {
|
|
|
+ // 跳转到结果页或回到房间页
|
|
|
+ Taro.redirectTo({
|
|
|
+ url: `/pages/room/result/index?roomId=${roomId.value}&gameId=${gameId.value}`
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ Taro.showToast({
|
|
|
+ title: turtleSoupStore.error || '结束游戏失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('结束游戏失败:', error)
|
|
|
+ Taro.hideLoading()
|
|
|
+ Taro.showToast({
|
|
|
+ title: '结束游戏失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 格式化时间
|
|
|
+ const formatTime = (timestamp?: number) => {
|
|
|
+ if (!timestamp) return ''
|
|
|
+
|
|
|
+ const now = Date.now()
|
|
|
+ const diff = now - timestamp
|
|
|
+
|
|
|
+ if (diff < 60000) {
|
|
|
+ // 不到1分钟
|
|
|
+ return '刚刚'
|
|
|
+ } else if (diff < 3600000) {
|
|
|
+ // 不到1小时
|
|
|
+ return `${Math.floor(diff / 60000)}分钟前`
|
|
|
+ } else if (diff < 86400000) {
|
|
|
+ // 不到1天
|
|
|
+ return `${Math.floor(diff / 3600000)}小时前`
|
|
|
+ } else {
|
|
|
+ // 超过1天
|
|
|
+ const date = new Date(timestamp)
|
|
|
+ return `${date.getMonth() + 1}月${date.getDate()}日 ${date.getHours()}:${String(date.getMinutes()).padStart(2, '0')}`
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 格式化回答
|
|
|
+ const formatAnswer = (answer?: TurtleSoupAnswerType) => {
|
|
|
+ if (!answer) return ''
|
|
|
+
|
|
|
+ switch (answer) {
|
|
|
+ case TurtleSoupAnswerType.YES:
|
|
|
+ return '是'
|
|
|
+ case TurtleSoupAnswerType.NO:
|
|
|
+ return '否'
|
|
|
+ case TurtleSoupAnswerType.IRRELEVANT:
|
|
|
+ return '不重要'
|
|
|
+ default:
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取回答样式类
|
|
|
+ const getAnswerClass = (answer?: TurtleSoupAnswerType) => {
|
|
|
+ if (!answer) return ''
|
|
|
+
|
|
|
+ switch (answer) {
|
|
|
+ case TurtleSoupAnswerType.YES:
|
|
|
+ return 'answer-yes'
|
|
|
+ case TurtleSoupAnswerType.NO:
|
|
|
+ return 'answer-no'
|
|
|
+ case TurtleSoupAnswerType.IRRELEVANT:
|
|
|
+ return 'answer-irrelevant'
|
|
|
+ default:
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 游戏刷新定时器
|
|
|
+ let gameRefreshInterval: NodeJS.Timeout | null = null
|
|
|
+
|
|
|
+ // 开始游戏监听
|
|
|
+ const startGameListener = () => {
|
|
|
+ // 每10秒刷新一次游戏数据
|
|
|
+ gameRefreshInterval = setInterval(async () => {
|
|
|
+ if (gameId.value) {
|
|
|
+ await turtleSoupStore.refreshGameData(gameId.value)
|
|
|
+
|
|
|
+ // 如果游戏已结束,跳转到结果页
|
|
|
+ if (turtleSoupStore.isGameEnded) {
|
|
|
+ stopGameListener()
|
|
|
+ Taro.redirectTo({
|
|
|
+ url: `/pages/room/result/index?roomId=${roomId.value}&gameId=${gameId.value}`
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, 10000)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 停止游戏监听
|
|
|
+ const stopGameListener = () => {
|
|
|
+ if (gameRefreshInterval) {
|
|
|
+ clearInterval(gameRefreshInterval)
|
|
|
+ gameRefreshInterval = null
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 页面加载时初始化
|
|
|
+ onMounted(() => {
|
|
|
+ initPage()
|
|
|
+ })
|
|
|
+
|
|
|
+ // 页面卸载时清理
|
|
|
+ onUnmounted(() => {
|
|
|
+ stopGameListener()
|
|
|
+ })
|
|
|
+
|
|
|
+ return {
|
|
|
+ // 数据
|
|
|
+ gameTitle,
|
|
|
+ statusText,
|
|
|
+ currentView,
|
|
|
+ hostView,
|
|
|
+ playerView,
|
|
|
+ isHost,
|
|
|
+ isGameActive,
|
|
|
+ gameProgress,
|
|
|
+ gameDuration,
|
|
|
+ pendingQuestions,
|
|
|
+ myQuestions,
|
|
|
+ revealedHints,
|
|
|
+ sortedQuestions,
|
|
|
+ questionDraft,
|
|
|
+ solutionDraft,
|
|
|
+ progressValue,
|
|
|
+ solverName,
|
|
|
+ solverSolution,
|
|
|
+ showProgressDialog,
|
|
|
+ showSolutionDialog,
|
|
|
+ showSolvedDialog,
|
|
|
+
|
|
|
+ // 方法
|
|
|
+ submitQuestion,
|
|
|
+ answerQuestion,
|
|
|
+ revealHint,
|
|
|
+ updateGameProgress,
|
|
|
+ confirmProgress,
|
|
|
+ submitSolution,
|
|
|
+ endGameWithSolvedStatus,
|
|
|
+ formatTime,
|
|
|
+ formatAnswer,
|
|
|
+ getAnswerClass,
|
|
|
+
|
|
|
+ // 枚举
|
|
|
+ TurtleSoupAnswerType
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss">
|
|
|
+.play-room-page {
|
|
|
+ padding: $spacing-base;
|
|
|
+ background-color: $background-color-base;
|
|
|
+ min-height: 100vh;
|
|
|
+ padding-bottom: $spacing-large * 4; // 为底部tabbar留出空间
|
|
|
|
|
|
- <script lang="ts">
|
|
|
- import Taro from '@tarojs/taro'
|
|
|
- import Tabbar from '@/components/Tabbar.vue'
|
|
|
+ .game-header {
|
|
|
+ padding: $spacing-base;
|
|
|
+ border-radius: $border-radius-base;
|
|
|
+ margin-bottom: $spacing-base;
|
|
|
+
|
|
|
+ &.host-header {
|
|
|
+ background-color: $background-color-orange; // 浅橙色背景
|
|
|
+ border-left: 4px solid $orange-color;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.player-header {
|
|
|
+ background-color: $background-color-blue; // 浅蓝色背景
|
|
|
+ border-left: 4px solid $blue-light-color;
|
|
|
+ }
|
|
|
+
|
|
|
+ .game-title {
|
|
|
+ font-size: $font-size-large;
|
|
|
+ font-weight: $font-weight-bold;
|
|
|
+ color: $text-color-primary;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: $spacing-small;
|
|
|
+
|
|
|
+ .tag {
|
|
|
+ margin-left: $spacing-base;
|
|
|
+ padding: $spacing-mini $spacing-base;
|
|
|
+ border-radius: $border-radius-mini;
|
|
|
+ font-size: $font-size-small;
|
|
|
+
|
|
|
+ &.host-tag {
|
|
|
+ background-color: $orange-color;
|
|
|
+ color: $text-color-light;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.player-tag {
|
|
|
+ background-color: $blue-light-color;
|
|
|
+ color: $text-color-light;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .game-info {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ .timer, .status {
|
|
|
+ font-size: $font-size-base;
|
|
|
+ color: $text-color-secondary;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ .nut-icon {
|
|
|
+ margin-right: $spacing-mini;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- export default {
|
|
|
- components: {
|
|
|
- Tabbar
|
|
|
- },
|
|
|
+ .game-content {
|
|
|
+ .scenario-card {
|
|
|
+ background-color: $background-color-light;
|
|
|
+ border-radius: $border-radius-base;
|
|
|
+ padding: $spacing-large;
|
|
|
+ margin-bottom: $spacing-large;
|
|
|
+ box-shadow: $shadow-light;
|
|
|
+
|
|
|
+ .scenario-title {
|
|
|
+ font-size: $font-size-medium;
|
|
|
+ font-weight: $font-weight-bold;
|
|
|
+ color: $text-color-primary;
|
|
|
+ margin-bottom: $spacing-base;
|
|
|
+ border-bottom: 1px solid $border-color-light;
|
|
|
+ padding-bottom: $spacing-small;
|
|
|
+ }
|
|
|
+
|
|
|
+ .scenario-text {
|
|
|
+ font-size: $font-size-base;
|
|
|
+ line-height: $line-height-loose;
|
|
|
+ color: $text-color-primary;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .progress-section {
|
|
|
+ margin-bottom: $spacing-large;
|
|
|
+
|
|
|
+ .progress-label {
|
|
|
+ font-size: $font-size-small;
|
|
|
+ color: $text-color-secondary;
|
|
|
+ margin-bottom: $spacing-small;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 主持人视图样式
|
|
|
+ .host-solution {
|
|
|
+ background-color: $background-color-orange;
|
|
|
+ border-radius: $border-radius-base;
|
|
|
+ padding: $spacing-large;
|
|
|
+ margin-bottom: $spacing-large;
|
|
|
+ box-shadow: $shadow-light;
|
|
|
+
|
|
|
+ .solution-title {
|
|
|
+ font-size: $font-size-medium;
|
|
|
+ font-weight: $font-weight-bold;
|
|
|
+ color: $orange-color;
|
|
|
+ margin-bottom: $spacing-base;
|
|
|
+ border-bottom: 1px solid rgba($orange-color, 0.2);
|
|
|
+ padding-bottom: $spacing-small;
|
|
|
+ }
|
|
|
+
|
|
|
+ .solution-text {
|
|
|
+ font-size: $font-size-base;
|
|
|
+ line-height: $line-height-loose;
|
|
|
+ color: $text-color-primary;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .hints-manager, .revealed-hints {
|
|
|
+ background-color: $background-color-light;
|
|
|
+ border-radius: $border-radius-base;
|
|
|
+ padding: $spacing-large;
|
|
|
+ margin-bottom: $spacing-large;
|
|
|
+ box-shadow: $shadow-light;
|
|
|
+
|
|
|
+ .hints-title {
|
|
|
+ font-size: $font-size-medium;
|
|
|
+ font-weight: $font-weight-bold;
|
|
|
+ color: $text-color-primary;
|
|
|
+ margin-bottom: $spacing-base;
|
|
|
+ border-bottom: 1px solid $border-color-light;
|
|
|
+ padding-bottom: $spacing-small;
|
|
|
+ }
|
|
|
+
|
|
|
+ .no-hints {
|
|
|
+ color: $text-color-secondary;
|
|
|
+ text-align: center;
|
|
|
+ padding: $spacing-large 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .hints-list {
|
|
|
+ .hint-item {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ padding: $spacing-base 0;
|
|
|
+ border-bottom: 1px solid $border-color-light;
|
|
|
+
|
|
|
+ &:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.revealed {
|
|
|
+ background-color: rgba($green-color, 0.05);
|
|
|
+ }
|
|
|
+
|
|
|
+ .hint-content {
|
|
|
+ flex: 1;
|
|
|
+ font-size: $font-size-base;
|
|
|
+ line-height: $line-height-loose;
|
|
|
+ color: $text-color-primary;
|
|
|
+ margin-right: $spacing-base;
|
|
|
+ }
|
|
|
+
|
|
|
+ .revealed-time {
|
|
|
+ font-size: $font-size-small;
|
|
|
+ color: $green-color;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // 生命周期钩子 - 页面显示
|
|
|
- onShow() {
|
|
|
- // 隐藏返回首页按钮
|
|
|
- Taro.hideHomeButton()
|
|
|
- console.log('已隐藏返回首页按钮')
|
|
|
- },
|
|
|
+ .pending-questions, .all-questions, .my-questions {
|
|
|
+ background-color: $background-color-light;
|
|
|
+ border-radius: $border-radius-base;
|
|
|
+ padding: $spacing-large;
|
|
|
+ margin-bottom: $spacing-large;
|
|
|
+ box-shadow: $shadow-light;
|
|
|
+
|
|
|
+ .questions-title, .all-questions-title, .questions-subtitle {
|
|
|
+ font-size: $font-size-medium;
|
|
|
+ font-weight: $font-weight-bold;
|
|
|
+ color: $text-color-primary;
|
|
|
+ margin-bottom: $spacing-base;
|
|
|
+ border-bottom: 1px solid $border-color-light;
|
|
|
+ padding-bottom: $spacing-small;
|
|
|
+ }
|
|
|
+
|
|
|
+ .no-questions {
|
|
|
+ color: $text-color-secondary;
|
|
|
+ text-align: center;
|
|
|
+ padding: $spacing-large 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .questions-list {
|
|
|
+ .question-item {
|
|
|
+ padding: $spacing-base;
|
|
|
+ border-bottom: 1px solid $border-color-light;
|
|
|
+ border-radius: $border-radius-small;
|
|
|
+ margin-bottom: $spacing-base;
|
|
|
+
|
|
|
+ &:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+ border-bottom: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .question-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: $spacing-small;
|
|
|
+
|
|
|
+ .asker-name {
|
|
|
+ font-size: $font-size-small;
|
|
|
+ font-weight: $font-weight-medium;
|
|
|
+ color: $text-color-primary;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ask-time {
|
|
|
+ font-size: $font-size-small;
|
|
|
+ color: $text-color-secondary;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .question-content {
|
|
|
+ font-size: $font-size-base;
|
|
|
+ color: $text-color-primary;
|
|
|
+ margin-bottom: $spacing-base;
|
|
|
+ line-height: $line-height-loose;
|
|
|
+ }
|
|
|
+
|
|
|
+ .answer-buttons {
|
|
|
+ display: flex;
|
|
|
+ gap: $spacing-base;
|
|
|
+ }
|
|
|
+
|
|
|
+ .question-answer {
|
|
|
+ font-size: $font-size-base;
|
|
|
+ font-weight: $font-weight-medium;
|
|
|
+ padding: $spacing-mini $spacing-base;
|
|
|
+ border-radius: $border-radius-mini;
|
|
|
+ display: inline-block;
|
|
|
+
|
|
|
+ &.answer-yes {
|
|
|
+ background-color: rgba($success-color, 0.1);
|
|
|
+ color: $success-color;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.answer-no {
|
|
|
+ background-color: rgba($danger-color, 0.1);
|
|
|
+ color: $danger-color;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.answer-irrelevant {
|
|
|
+ background-color: rgba($text-color-secondary, 0.1);
|
|
|
+ color: $text-color-secondary;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .question-pending {
|
|
|
+ font-size: $font-size-small;
|
|
|
+ color: $text-color-secondary;
|
|
|
+ font-style: italic;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // Composition API
|
|
|
- setup() {
|
|
|
- // 这里可以添加游戏进行中页面的逻辑
|
|
|
+ .question-section {
|
|
|
+ background-color: $background-color-light;
|
|
|
+ border-radius: $border-radius-base;
|
|
|
+ padding: $spacing-large;
|
|
|
+ margin-bottom: $spacing-large;
|
|
|
+ box-shadow: $shadow-light;
|
|
|
|
|
|
- return {
|
|
|
- // 返回需要在模板中使用的数据和方法
|
|
|
+ .question-title {
|
|
|
+ font-size: $font-size-medium;
|
|
|
+ font-weight: $font-weight-bold;
|
|
|
+ color: $text-color-primary;
|
|
|
+ margin-bottom: $spacing-base;
|
|
|
+ border-bottom: 1px solid $border-color-light;
|
|
|
+ padding-bottom: $spacing-small;
|
|
|
}
|
|
|
- },
|
|
|
+
|
|
|
+ .question-input {
|
|
|
+ margin-bottom: $spacing-large;
|
|
|
+
|
|
|
+ .nut-textarea {
|
|
|
+ margin-bottom: $spacing-base;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // 生命周期钩子 - 页面加载
|
|
|
- onLoad() {
|
|
|
- // 页面加载时的初始化逻辑
|
|
|
+ .host-controls, .player-controls {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: $spacing-base;
|
|
|
+ margin-bottom: $spacing-large;
|
|
|
}
|
|
|
}
|
|
|
- </script>
|
|
|
|
|
|
- <style lang="scss">
|
|
|
- .play-room-page {
|
|
|
- padding: 20px;
|
|
|
-
|
|
|
- .title {
|
|
|
- font-size: 20px;
|
|
|
- font-weight: bold;
|
|
|
- margin-bottom: 20px;
|
|
|
+ // 弹窗样式
|
|
|
+ .progress-dialog, .solution-dialog, .solved-dialog {
|
|
|
+ padding: $spacing-base;
|
|
|
+
|
|
|
+ .progress-label {
|
|
|
+ margin-bottom: $spacing-base;
|
|
|
+ font-size: $font-size-small;
|
|
|
+ color: $text-color-secondary;
|
|
|
text-align: center;
|
|
|
}
|
|
|
+
|
|
|
+ .nut-range {
|
|
|
+ margin-bottom: $spacing-large;
|
|
|
+ }
|
|
|
+
|
|
|
+ .nut-textarea {
|
|
|
+ margin-bottom: $spacing-large;
|
|
|
+ }
|
|
|
+
|
|
|
+ .solver-input {
|
|
|
+ margin-bottom: $spacing-base;
|
|
|
+ }
|
|
|
+
|
|
|
+ .dialog-buttons {
|
|
|
+ margin-top: $spacing-base;
|
|
|
+ }
|
|
|
}
|
|
|
- </style>
|
|
|
+}
|
|
|
+</style>
|