|
2 tuntia sitten | |
---|---|---|
.cursor | 1 viikko sitten | |
config | 1 viikko sitten | |
src | 2 tuntia sitten | |
types | 1 viikko sitten | |
.editorconfig | 1 viikko sitten | |
.eslintrc | 1 viikko sitten | |
.gitignore | 1 viikko sitten | |
README.md | 20 tuntia sitten | |
babel.config.js | 1 viikko sitten | |
components.d.ts | 5 tuntia sitten | |
package.json | 5 tuntia sitten | |
pnpm-lock.yaml | 5 tuntia sitten | |
project.config.json | 1 päivä sitten | |
project.tt.json | 1 viikko sitten | |
tsconfig.json | 1 viikko sitten |
产品名称:基于微信小程序的排队解闷小游戏合集
产品愿景:将排队时的无聊等待转变为社交互动的契机,通过线上小游戏引导线下交流,增进陌生人或团队成员间的互动与了解。
核心价值主张:
创建房间(主持人)
加入房间
主持人(游戏创建者)
玩家
海龟汤(首发核心游戏)
其他游戏类型(后续拓展)
客户端 (Taro)
↑↓
云开发 API
↑↓
云函数 (业务逻辑)
↑↓
云数据库 (数据存储)
接口名称 | 功能描述 | 参数 | 返回值 |
---|
接口名称 | 功能描述 | 参数 | 返回值 |
---|
HostOnly组件:仅主持人可见内容
<template>
<slot v-if="isHost"></slot>
</template>
<script setup lang="ts">
import { useRoomRole } from '@/hooks/useRoomRole';
const props = defineProps<{
roomId: string
}>();
const { isHost } = useRoomRole(props.roomId);
</script>
PlayerOnly组件:仅玩家可见内容
<template>
<slot v-if="isPlayer"></slot>
</template>
<script setup lang="ts">
import { useRoomRole } from '@/hooks/useRoomRole';
const props = defineProps<{
roomId: string
}>();
const { isPlayer } = useRoomRole(props.roomId);
</script>
g src/ ├── app.config.ts # 小程序全局配置 ├── app.scss # 全局样式 ├── app.ts # 应用入口 ├── assets/ # 静态资源 │ ├── images/ # 图片资源 │ └── styles/ # 样式资源 │ ├── variables.scss # 样式变量 │ ├── nutui-custom.scss # nutui样式 │ └── mixins.scss # 样式混合 ├── components/ # 全局组件 │ ├── HostOnly/ │ └── PlayerOnly/ ├── composables/ # 可组合式函数 │ └── useRoomRole.ts ├── custom-tab-bar/ # 自定义tabbar ├── pages/ # 页面 │ ├── index/ # 游戏广场 │ ├── game-detail/ # 游戏详情 │ ├── room/ # 房间相关页面 │ │ ├── create/ # 创建房间(主持人专用) │ │ ├── join/ # 加入房间(玩家专用) │ │ ├── waiting/ # 等待室(带角色参数) │ │ └── play/ # 游戏进行中(带角色参数) │ ├── profile/ # 个人中心 │ └── history/ # 游戏历史 ├── services/ │ ├── api/ │ │ ├── index.ts # API 入口点,导出所有 API │ │ ├── game.ts # 游戏列表/通用游戏信息的 API │ │ ├── room.ts # 房间管理 API │ │ └── games/ # 特定游戏 API 目录 │ │ ├── index.ts # 导出所有游戏 API │ │ ├── turtlesoup.ts # 海龟汤游戏 API │ │ ├── werewolf.ts # 狼人杀游戏 API │ │ └── script.ts # 剧本杀游戏 API │ └── cloud.ts # 云函数调用封装 ├── stores/ # Pinia状态管理 │ ├── index.ts # Store 入口点,导出所有 Store │ ├── user.ts # 用户 Store │ ├── room.ts # 房间 Store │ ├── game.ts # 游戏列表/通用游戏 Store │ └── games/ # 特定游戏 Store 目录 │ ├── index.ts # 导出所有游戏 Store │ ├── turtlesoup.ts # 海龟汤游戏 Store │ ├── werewolf.ts # 狼人杀游戏 Store │ └── script.ts # 剧本杀游戏 Store ├── types/ # 数据结构定义 │ ├── global.d.ts # 全局 │ ├── user.ts # 用户数据结构 │ ├── room.ts # 房间数据结构 │ ├── game.ts # 游戏定义数据结构 │ └── games/ # 特定游戏 数据结构 目录 │ ├── index.ts # 导出所有游戏 数据结构 │ ├── turtlesoup.ts # 海龟汤游戏 数据结构 │ ├── werewolf.ts # 狼人杀游戏 数据结构 │ └── script.ts # 剧本杀游戏 数据结构 └── utils/ # 工具函数
├── common.ts # 通用工具
├── format.ts # 格式化工具
└── storage.ts # 存储工具
useRoomRole
组合式API获取和验证用户角色// 根据角色过滤游戏数据
function filterGameDataByRole(gameData, role: RoomRole) {
if (role === RoomRole.HOST) {
// 主持人可以看到所有数据
return gameData;
} else {
// 玩家只能看到部分数据
return {
...gameData,
initialStory: gameData.initialStory,
revealedHints: gameData.revealedHints,
// 隐藏未公开信息
solution: undefined,
unreveaedHints: undefined,
secretNotes: undefined
};
}
}
// hooks/useRoomRole.ts
import { ref, onMounted, computed } from 'vue';
import Taro from '@tarojs/taro';
import { RoomRole } from '@/types';
export function useRoomRole(roomId: string) {
const role = ref<RoomRole | null>(null);
onMounted(() => {
// 从路由参数获取角色
const params = Taro.getCurrentInstance().router?.params;
let roleFromParams = params?.role as RoomRole;
// 如果没有,从服务器获取
if (!roleFromParams && roomId) {
Taro.cloud.callFunction({
name: 'getRoomMemberRole',
data: { roomId }
}).then(res => {
role.value = res.result.role;
});
} else {
role.value = roleFromParams;
}
});
const isHost = computed(() => role.value === RoomRole.HOST);
const isPlayer = computed(() => role.value === RoomRole.PLAYER);
return {
role,
isHost,
isPlayer
};
}
// composables/useRoomData.ts
import { ref, onMounted, onUnmounted } from 'vue';
import Taro from '@tarojs/taro';
import type { Room } from '@/types';
export function useRoomData(roomId: string) {
const roomData = ref<Room | null>(null);
let watcher = null;
// 设置房间数据监听
onMounted(() => {
const db = Taro.cloud.database();
watcher = db.collection('rooms')
.doc(roomId)
.watch({
onChange: function(snapshot) {
roomData.value = snapshot.docs[0];
},
onError: function(err) {
console.error('监听房间失败', err);
}
});
});
// 组件卸载时关闭监听
onUnmounted(() => {
if (watcher) {
watcher.close();
}
});
return {
roomData
};
}