소스 검색

feat: 优化结构,拆分功能

zhusiqing 3 년 전
부모
커밋
d697c5a7fd

+ 1 - 0
src/components.d.ts

@@ -6,6 +6,7 @@ declare module 'vue' {
   export interface GlobalComponents {
     AButton: typeof import('ant-design-vue/es')['Button'];
     ASpin: typeof import('ant-design-vue/es')['Spin'];
+    Card: typeof import('./components/Card/index.vue')['default'];
     InitLoading: typeof import('./components/InitLoading/index.vue')['default'];
     MinusOutlined: typeof import('@ant-design/icons-vue')['MinusOutlined'];
     PlusOutlined: typeof import('@ant-design/icons-vue')['PlusOutlined'];

+ 100 - 0
src/components/Card/index.vue

@@ -0,0 +1,100 @@
+<template>
+  <div class="card" :class="{ reverse: isReverse }" @click="click">
+    <div class="front">
+      {{ props.num }}
+    </div>
+    <div class="back">
+      <div class="number">{{ props.num }}</div>
+      <div class="word">{{ props.text }}</div>
+      <div class="confirm">
+        <a-button class="btn" type="primary" @click.stop="rememberClick">我记住啦</a-button>
+      </div>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+  const props = defineProps({
+    status: Number,
+    num: Number,
+    text: String
+  });
+  const emit = defineEmits(['remember', 'update:status']);
+  const _status = computed({
+    get() {
+      return props.status;
+    },
+    set(val) {
+      emit('update:status', val);
+    }
+  });
+  const isReverse = computed(() => _status.value === 1);
+  // 卡片点击查看
+  const click = () => {
+    _status.value = 1;
+  };
+  // 我记住啦
+  const rememberClick = () => {
+    emit('remember');
+  };
+</script>
+<style lang="less" scoped>
+  @yellow: var(--color-yellow);
+  .card {
+    position: absolute;
+    display: flex;
+    align-items: center;
+    flex-direction: column;
+    width: 200px;
+    height: 300px;
+    text-align: center;
+    &.reverse {
+      z-index: 10;
+      .front {
+        transform: rotateY(180deg);
+      }
+      .back {
+        transform: rotateY(360deg);
+      }
+    }
+    .front,
+    .back {
+      position: absolute;
+      width: 100%;
+      height: 100%;
+      transition: transform 1s ease;
+      backface-visibility: hidden;
+      -webkit-backface-visibility: hidden;
+      background-color: @yellow;
+      box-shadow: 2px 2px 10px 1px rgba(0, 0, 0, 0.2);
+    }
+    .front {
+      transform: rotateY(0);
+      z-index: 2;
+      line-height: 300px;
+      font-size: 46px;
+    }
+    .back {
+      transform: rotateY(180deg);
+      z-index: 1;
+    }
+    .number {
+      text-align: center;
+      font-size: 30px;
+      padding-top: 30px;
+    }
+    .word {
+      padding-top: 30px;
+      font-size: 36px;
+    }
+    .confirm {
+      padding-top: 20px;
+      .btn {
+        background-color: #141e30;
+        border: none;
+        color: @yellow;
+        width: 160px;
+        height: 40px;
+      }
+    }
+  }
+</style>

+ 1 - 0
src/main.ts

@@ -3,6 +3,7 @@ import App from './App.vue';
 import { setupRouter } from './router';
 import { setupStore } from './store';
 import 'ant-design-vue/es/message/style';
+import 'ant-design-vue/es/modal/style';
 import 'nprogress/nprogress.css';
 
 function initApp() {

+ 210 - 0
src/pages/Game/components/Playing.vue

@@ -0,0 +1,210 @@
+<template>
+  <div ref="playing" class="playing">
+    <template v-for="(player, key) in players" :key="key">
+      <div
+        class="player"
+        :class="{
+          select: player.status === 1,
+          disabled: isDisabled && currentFocus !== key,
+          out: player.status === 2
+        }"
+        @click="() => focusClick(key)"
+        >{{ player.num }}</div
+      >
+    </template>
+  </div>
+  <div v-if="isVote" class="operate">
+    <a-button class="btn forget" type="primary" @click="forget">忘词</a-button>
+    <a-button class="btn vote" type="primary" @click="vote">投票</a-button>
+  </div>
+  <div v-if="isForget && currentPlayer" class="mask" @click="closeForget">
+    <div class="forget-cards">
+      <div class="number">{{ currentPlayer.num }}</div>
+      <div class="word">{{ currentPlayer.text }}</div>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+  import type { PropType } from 'vue';
+  import { EnumIdentity } from '@/utils/enum';
+
+  const propsPlaying = defineProps({
+    players: {
+      type: Array as PropType<InterfacePlayer[]>,
+      default: () => []
+    }
+  });
+  const { players } = toRefs(propsPlaying);
+  const emitPlaying = defineEmits(['over']);
+  const playing = ref(null);
+  // 当前哪个玩家被选中
+  const currentFocus = ref(-1);
+  const isDisabled = ref(false);
+  // 是否要进行看词或者投票
+  const isVote = computed(() => currentFocus.value !== -1);
+  // 当前操作的玩家
+  const currentPlayer = ref<InterfacePlayer | null>(null);
+  // 查看词
+  const isForget = ref(false);
+  // 选中状态切换
+  onClickOutside(playing, () => {
+    if (currentFocus.value !== -1) {
+      currentFocus.value = -1;
+      isDisabled.value = false;
+    }
+  });
+  // 选中玩家
+  const focusClick = (key: number) => {
+    const player = propsPlaying.players[key];
+    // 踢出了,就没有操作了
+    if (player.status === 2) {
+      return;
+    }
+    isDisabled.value = true;
+    currentFocus.value = key;
+    currentPlayer.value = player;
+  };
+  // 忘词
+  const forget = () => {
+    isForget.value = true;
+  };
+  // 关闭忘词
+  const closeForget = () => {
+    isForget.value = false;
+    currentPlayer.value = null;
+  };
+  // 投票/结算
+  const vote = () => {
+    const status = currentPlayer.value?.status;
+    // 出局
+    if (currentPlayer.value) {
+      currentPlayer.value.status = 2;
+    }
+    const filterPlayer = players.value.filter(el => el.status !== 2);
+    const filterPlayerNum = filterPlayer.length;
+    const filterSpy = filterPlayer.filter(el => el.identity === EnumIdentity.spy);
+    const filterSpyNum = filterSpy.length;
+    if (!filterSpyNum) {
+      alert('游戏结束,平民胜利');
+      emitPlaying('over');
+      return;
+    }
+    const filterCivilian = filterPlayer.filter(el => el.identity === EnumIdentity.civilian);
+    const filterCivilianNum = filterCivilian.length;
+    if (filterSpyNum >= filterCivilianNum) {
+      alert('游戏结束,卧底胜利');
+      emitPlaying('over');
+      return;
+    }
+    // 如果当前是选中的第一个玩家,则自动延伸到下一个玩家
+    if (status === 1) {
+      const findIndex = players.value.findIndex(el => el.num === currentPlayer.value?.num);
+      let index = -1;
+      if (findIndex === players.value.length - 1) {
+        index = 0;
+      } else {
+        index = findIndex + 1;
+      }
+      players.value[index].status = 1;
+    }
+  };
+</script>
+<style lang="less" scoped>
+  @yellow: var(--color-yellow);
+  @blue: var(--color-blue);
+  @red: var(--color-red);
+  @text: var(--color-text);
+  .playing {
+    display: flex;
+    text-align: center;
+    justify-content: center;
+    flex-wrap: wrap;
+    padding-top: 40px;
+    .player {
+      width: 60px;
+      height: 60px;
+      border: 1px solid @yellow;
+      border-radius: 50%;
+      margin: 20px 10px;
+      line-height: 60px;
+      font-size: 30px;
+      color: @yellow;
+      font-weight: 600;
+      &.select {
+        background-color: @yellow;
+        color: @blue;
+      }
+      &.disabled {
+        border-color: rgba(255, 255, 255, 0.2);
+        color: rgba(255, 255, 255, 0.2);
+        background-color: transparent;
+      }
+      &.out {
+        position: relative;
+        &::before {
+          content: ' ';
+          position: absolute;
+          width: 8px;
+          height: 100%;
+          background-color: @red;
+          transform-origin: 50% 58%;
+          transform: rotateZ(45deg);
+        }
+        &::after {
+          content: ' ';
+          position: absolute;
+          width: 8px;
+          height: 100%;
+          background-color: @red;
+          transform-origin: 0 70%;
+          transform: rotateZ(-45deg);
+        }
+      }
+    }
+  }
+  .operate {
+    display: flex;
+    justify-content: space-around;
+    padding-top: 40px;
+    .btn {
+      width: 140px;
+      height: 50px;
+      font-size: 26px;
+      border-radius: 6px;
+      border: none;
+    }
+    .forget {
+      color: @text;
+      background-color: @yellow;
+    }
+    .vote {
+      color: @text;
+      background-color: @red;
+    }
+  }
+  .mask {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100vw;
+    height: 100vh;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    background-color: rgba(0, 0, 0, 0.6);
+    .forget-cards {
+      width: 200px;
+      height: 300px;
+      background-color: @yellow;
+      text-align: center;
+      .number {
+        font-size: 32px;
+        padding-top: 50px;
+      }
+      .word {
+        font-size: 36px;
+        padding-top: 40px;
+      }
+    }
+  }
+</style>

+ 41 - 0
src/pages/Game/components/ReadWords.vue

@@ -0,0 +1,41 @@
+<template>
+  <div class="read-words">
+    <div class="cards">
+      <template v-for="(word, key) in readWords" :key="`${key}-${word.num}`">
+        <Card
+          v-model:status="word.status"
+          class="card"
+          :num="key + 1"
+          :text="word.text"
+          :style="{ left: `${key * 3}px`, top: `${key * 10}px` }"
+          @remember="remember"
+        ></Card>
+      </template>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+  import type { PropType } from 'vue';
+
+  const propsReadWords = defineProps({
+    readWords: {
+      type: Array as PropType<InterfacePlayer[]>,
+      default: () => []
+    }
+  });
+  const { readWords } = toRefs(propsReadWords);
+  const emitpropsReadWords = defineEmits(['update:readWords']);
+  // 我记住啦
+  const remember = () => {
+    readWords.value.pop();
+  };
+</script>
+<style lang="less" scoped>
+  .read-words {
+    padding-top: 40px;
+    .cards {
+      position: relative;
+      margin-left: 80px;
+    }
+  }
+</style>

+ 3 - 0
src/pages/Game/composables/index.ts

@@ -0,0 +1,3 @@
+export * from './session';
+export * from './words';
+export * from './player';

+ 40 - 0
src/pages/Game/composables/player.ts

@@ -0,0 +1,40 @@
+import { session, initSession } from '@/utils/storage';
+import { EnumIdentity } from '@/utils/enum';
+interface InterfacePlayerOptions {
+  playerNum: number;
+  civilianWord: string;
+  spyWord: string;
+  spyKeys: number[];
+  whiteKeys: number[];
+  selectKey: number;
+}
+
+export const usePlayer = (options: InterfacePlayerOptions) => {
+  const { playerNum, civilianWord, spyWord, spyKeys, whiteKeys, selectKey } = options;
+  // 初始化的底层数组
+  const list = new Array(playerNum).fill(1).map((el, i) => {
+    return {
+      num: ++i,
+      text: civilianWord,
+      status: 0,
+      identity: EnumIdentity.civilian
+    };
+  });
+
+  // 设置
+  spyKeys.forEach(key => {
+    list[key].identity = EnumIdentity.spy;
+    list[key].text = spyWord;
+  });
+  whiteKeys.forEach(key => {
+    list[key].identity = EnumIdentity.white;
+    list[key].text = '你是个白板';
+  });
+  const readWords = reactive(list.map(el => ({ ...el })));
+  const players = reactive(list.map(el => ({ ...el })));
+  players[selectKey].status = 1;
+  return {
+    readWords,
+    players
+  };
+};

+ 62 - 0
src/pages/Game/composables/session.ts

@@ -0,0 +1,62 @@
+import { session, initSession } from '@/utils/storage';
+
+export const useGetSession = () => {
+  // 词组
+  const civilianWord = session.value.civilianWord || '';
+  const spyWord = session.value.spyWord || '';
+  // 玩家数
+  const playerNum = session.value.player;
+  // 卧底数
+  const spyNum = session.value.spy;
+  // 白板数
+  const whiteNum = session.value.white;
+  // 对应角色的key组
+  const spyKeys = session.value.spyKeys;
+  const whiteKeys = session.value.whiteKeys;
+  // 选中玩家key
+  const selectKey = session.value.selectKey;
+  // 当前环节状态
+  const currentStatus = session.value.currentStatus;
+  // 初始化
+  const setInitSession = () => (session.value = initSession);
+  const setSession = (
+    key:
+      | 'player'
+      | 'spy'
+      | 'white'
+      | 'currentStatus'
+      | 'selectKey'
+      | 'spyKeys'
+      | 'whiteKeys'
+      | 'civilianWord'
+      | 'spyWord',
+    value: string | number | number[]
+  ) => {
+    switch (key) {
+      case 'spyKeys':
+      case 'whiteKeys':
+        session.value[key] = value as number[];
+        break;
+      case 'civilianWord':
+      case 'spyWord':
+        session.value[key] = value as string;
+        break;
+      default:
+        session.value[key] = value as number;
+        break;
+    }
+  };
+  return {
+    civilianWord,
+    spyWord,
+    playerNum,
+    spyNum,
+    whiteNum,
+    spyKeys,
+    whiteKeys,
+    selectKey,
+    currentStatus,
+    setInitSession,
+    setSession
+  };
+};

+ 15 - 0
src/pages/Game/composables/words.ts

@@ -0,0 +1,15 @@
+import { wordsList } from '@/utils/words';
+
+export const useWords = (civilianWord = '', spyWord = '') => {
+  // 是否要存入session
+  let isSetWordStorage = false;
+  // 生成随机组词并放入缓存
+  if (!civilianWord || !spyWord) {
+    const wordsListNum = wordsList.length;
+    const selectWordKey = Math.floor(Math.random() * wordsListNum);
+    const selectWord = wordsList[selectWordKey];
+    [civilianWord, spyWord] = selectWord.split(',');
+    isSetWordStorage = true;
+  }
+  return { civilianWord, spyWord, isSetWordStorage };
+};

+ 71 - 352
src/pages/Game/index.vue

@@ -5,37 +5,27 @@
       <reload-outlined class="restart" @click="restart" />
     </div>
     <div class="tip">{{
-      isGaming ? '请选中的玩家描述所见的词' : '请玩家依次传手机查看自己的词'
+      isPlaying ? '请选中的玩家描述所见的词' : '请玩家依次传手机查看自己的词'
     }}</div>
-    <template v-if="!isGaming">
-      <div class="content">
+    <template v-if="!isPlaying">
+      <ReadWordsComponent :read-words="readWords"></ReadWordsComponent>
+      <!-- <div class="content">
         <div class="cards">
           <template v-for="(word, key) in readWords" :key="`${key}-${word.num}`">
-            <div
-              class="card"
-              :class="{ reverse: word.status === 1 }"
+            <Card
+              v-model:status="word.status"
+              :num="key + 1"
+              :text="word.text"
+              @remember="rememberClick"
               :style="{ left: `${key * 3}px`, top: `${key * 10}px` }"
-              @click="() => cardClick(key)"
-            >
-              <div class="front">
-                {{ key + 1 }}
-              </div>
-              <div class="back">
-                <div class="number">{{ key + 1 }}</div>
-                <div class="word">{{ word.text }}</div>
-                <div class="confirm">
-                  <a-button class="btn" type="primary" @click.stop="rememberClick"
-                    >我记住啦</a-button
-                  >
-                </div>
-              </div>
-            </div>
+            ></Card>
           </template>
         </div>
-      </div>
+      </div> -->
     </template>
     <template v-else>
-      <div ref="gaming" class="gaming">
+      <PlayComponent :players="players" @over="init"></PlayComponent>
+      <!-- <div ref="gaming" class="gaming">
         <template v-for="(player, key) in players" :key="key">
           <div
             class="player"
@@ -58,195 +48,86 @@
           <div class="number">{{ currentPlayer.num }}</div>
           <div class="word">{{ currentPlayer.text }}</div>
         </div>
-      </div>
+      </div> -->
     </template>
   </div>
 </template>
 <script lang="ts" setup>
-  import { session, initSession } from '@/utils/storage';
   import { Modal } from 'ant-design-vue/es';
-  import 'ant-design-vue/es/modal/style';
-  import { wordsList } from '@/utils/words';
-  interface InterfacePlayer {
-    num: number;
-    text: string;
-    status: number;
-    identity: number;
-  }
-  enum EnumStatus {
-    init = 0,
-    finish = 1
+  import { useGetSession, useWords, usePlayer } from './composables';
+  import { randomPlayer } from '@/utils/tools';
+  import ReadWordsComponent from './components/ReadWords.vue';
+  import PlayComponent from './components/Playing.vue';
+  enum EnumGameStatus {
+    word = 1,
+    game = 2
   }
-  enum EnumIdentity {
-    civilian = 1,
-    spy = 2,
-    white = 3
-  }
-  // 取缓存词组
-  let civilianWord = session.value.civilianWord || '';
-  let spyWord = session.value.spyWord || '';
-  // 生成随机组词并放入缓存
-  if (!civilianWord || !spyWord) {
-    const wordsListNum = wordsList.length;
-    const selectWordKey = Math.floor(Math.random() * wordsListNum);
-    const selectWord = wordsList[selectWordKey];
-    [civilianWord, spyWord] = selectWord.split(',');
-    session.value.civilianWord = civilianWord;
-    session.value.spyWord = spyWord;
-  }
-
   const router = useRouter();
-  let playerNums = session.value.player;
-  if (!playerNums) {
-    playerNums = 4;
-    router.replace('/login');
+  let {
+    civilianWord: cacheCivilianWord,
+    spyWord: cacheSpyWord,
+    playerNum,
+    spyNum,
+    whiteNum,
+    spyKeys,
+    whiteKeys,
+    selectKey,
+    currentStatus: cacheCurrentStatus,
+    setInitSession,
+    setSession
+  } = useGetSession();
+  const { civilianWord, spyWord, isSetWordStorage } = useWords(cacheCivilianWord, cacheSpyWord);
+  // 更新缓存词组
+  if (isSetWordStorage) {
+    setSession('civilianWord', civilianWord);
+    setSession('spyWord', spyWord);
   }
-  const list = new Array(playerNums).fill(1).map((el, i) => {
-    return {
-      num: ++i,
-      text: civilianWord,
-      status: 0,
-      identity: EnumIdentity.civilian
-    };
-  });
-  // 生成随机数组
-  const randomPlayer = (sum: number, num: number, exist: number[] = []): number[] => {
-    const arr: number[] = [];
-    for (let i = 0; i < num; i++) {
-      const r = Math.floor(Math.random() * sum);
-      if (arr.includes(r) || exist.includes(r)) {
-        i--;
-      } else {
-        arr.push(r);
-      }
-    }
-    return arr;
-  };
-  // 对应的key组
-  let spyKeys = session.value.spyKeys;
-  let whiteKeys = session.value.whiteKeys;
+  // 玩家获取异常处理
+  if (!playerNum) {
+    playerNum = 4;
+    router.replace('login');
+  }
+  // 生成随机key
   if (!spyKeys) {
-    spyKeys = randomPlayer(playerNums, session.value.spy);
-    session.value.spyKeys = spyKeys;
+    const keys = randomPlayer(playerNum, spyNum);
+    spyKeys = keys;
+    setSession('spyKeys', keys);
   }
+  // 生成随机key
   if (!whiteKeys) {
-    whiteKeys = randomPlayer(playerNums, session.value.white, spyKeys);
-    session.value.whiteKeys = whiteKeys;
+    const keys = randomPlayer(playerNum, whiteNum, spyKeys);
+    whiteKeys = keys;
+    setSession('whiteKeys', keys);
   }
-  // 设置
-  spyKeys.forEach(key => {
-    list[key].identity = EnumIdentity.spy;
-    list[key].text = spyWord;
-  });
-  whiteKeys.forEach(key => {
-    list[key].identity = EnumIdentity.white;
-    list[key].text = '';
-  });
-  const readWords = reactive(list.map(el => ({ ...el })));
-  const players = reactive(list.map(el => ({ ...el })));
   // 选中玩家的key
-  const selectKey =
-    session.value.selectKey === undefined
-      ? Math.floor(Math.random() * playerNums)
-      : session.value.selectKey;
-  players[selectKey].status = 1;
-  session.value.selectKey = selectKey;
-  // 当前环节
-  const currentStatus = ref(session.value.currentStatus);
-  // 当前哪个玩家被选中
-  const currentFocus = ref(-1);
-  const gaming = ref(null);
-  const isDisabled = ref(false);
-  // 是否是游戏进行环节
-  const isGaming = computed(() => currentStatus.value === EnumStatus.finish);
-  // 是否要进行看词或者投票
-  const isVote = computed(() => currentFocus.value !== -1);
-  // 当前操作的玩家
-  const currentPlayer = ref<InterfacePlayer | null>(null);
-  // 查看词
-  const isForget = ref(false);
-  // 选中状态切换
-  onClickOutside(gaming, () => {
-    if (currentFocus.value !== -1) {
-      currentFocus.value = -1;
-      isDisabled.value = false;
-    }
+  if (selectKey === undefined) {
+    selectKey = Math.floor(Math.random() * playerNum);
+    setSession('selectKey', selectKey);
+  }
+  const { readWords, players } = usePlayer({
+    playerNum,
+    civilianWord,
+    spyWord,
+    spyKeys,
+    whiteKeys,
+    selectKey
   });
+
+  // 当前环节
+  const currentStatus = ref(cacheCurrentStatus);
+  const isPlaying = computed(() => currentStatus.value === EnumGameStatus.game);
+
   // 玩家查看词的情况
   watch(readWords, p => {
     if (!p.length) {
-      const status = EnumStatus.finish;
+      const status = EnumGameStatus.game;
       currentStatus.value = status;
-      session.value.currentStatus = status;
+      setSession('currentStatus', status);
     }
   });
-
-  // 卡片点击查看
-  const cardClick = (key: number) => {
-    readWords[key].status = 1;
-  };
-  // 我记住啦
-  const rememberClick = () => {
-    readWords.pop();
-  };
-  // 选中玩家
-  const focusClick = (key: number) => {
-    const player = players[key];
-    // 踢出了,就没有操作了
-    if (player.status === 2) {
-      return;
-    }
-    isDisabled.value = true;
-    currentFocus.value = key;
-    currentPlayer.value = player;
-  };
-  // 忘词
-  const forget = () => {
-    isForget.value = true;
-  };
-  // 关闭忘词
-  const closeForget = () => {
-    isForget.value = false;
-    currentPlayer.value = null;
-  };
-  // 投票/结算
-  const vote = () => {
-    const status = currentPlayer.value?.status;
-    // 出局
-    if (currentPlayer.value) {
-      currentPlayer.value.status = 2;
-    }
-    const filterPlayer = players.filter(el => el.status !== 2);
-    const filterPlayerNum = filterPlayer.length;
-    const filterSpy = filterPlayer.filter(el => el.identity === EnumIdentity.spy);
-    const filterSpyNum = filterSpy.length;
-    if (!filterSpyNum) {
-      alert('游戏结束,平民胜利');
-      init();
-      return;
-    }
-    const filterCivilian = filterPlayer.filter(el => el.identity === EnumIdentity.civilian);
-    const filterCivilianNum = filterCivilian.length;
-    if (filterSpyNum >= filterCivilianNum) {
-      alert('游戏结束,卧底胜利');
-      init();
-      return;
-    }
-    // 如果当前是选中的第一个玩家,则自动延伸到下一个玩家
-    if (status === 1) {
-      const findIndex = players.findIndex(el => el.num === currentPlayer.value?.num);
-      let index = -1;
-      if (findIndex === players.length - 1) {
-        index = 0;
-      } else {
-        index = findIndex + 1;
-      }
-      players[index].status = 1;
-    }
-  };
   // 初始化
   function init() {
-    session.value = initSession;
+    setInitSession();
     router.replace('/login');
   }
   // 重新开始
@@ -263,10 +144,8 @@
   };
 </script>
 <style lang="less" scoped>
-  @yellow: var(--color-yellow);
   @blue: var(--color-blue);
   @text: var(--color-text);
-  @red: var(--color-red);
   .game {
     height: 100%;
     background-color: @blue;
@@ -283,165 +162,5 @@
       color: @text;
       padding-top: 30px;
     }
-    .content {
-      padding-top: 40px;
-      .cards {
-        position: relative;
-        margin-left: 70px;
-        .card {
-          position: absolute;
-          display: flex;
-          align-items: center;
-          flex-direction: column;
-          width: 200px;
-          height: 300px;
-          top: 0;
-          left: 0;
-          text-align: center;
-          &.reverse {
-            z-index: 10;
-            .front {
-              transform: rotateY(180deg);
-            }
-            .back {
-              transform: rotateY(360deg);
-            }
-          }
-          .front,
-          .back {
-            position: absolute;
-            width: 100%;
-            height: 100%;
-            transition: transform 1s ease;
-            backface-visibility: hidden;
-            -webkit-backface-visibility: hidden;
-            background-color: @yellow;
-            box-shadow: 2px 2px 10px 1px rgba(0, 0, 0, 0.2);
-          }
-          .front {
-            transform: rotateY(0);
-            z-index: 2;
-            line-height: 300px;
-            font-size: 46px;
-          }
-          .back {
-            transform: rotateY(180deg);
-            z-index: 1;
-          }
-          .number {
-            text-align: center;
-            font-size: 30px;
-            padding-top: 30px;
-          }
-          .word {
-            padding-top: 30px;
-            font-size: 36px;
-          }
-          .confirm {
-            padding-top: 20px;
-            .btn {
-              background-color: #141e30;
-              border: none;
-              color: @yellow;
-              width: 160px;
-              height: 40px;
-            }
-          }
-        }
-      }
-    }
-    .gaming {
-      display: flex;
-      text-align: center;
-      justify-content: center;
-      flex-wrap: wrap;
-      padding-top: 40px;
-      .player {
-        width: 60px;
-        height: 60px;
-        border: 1px solid @yellow;
-        border-radius: 50%;
-        margin: 20px 10px;
-        line-height: 60px;
-        font-size: 30px;
-        color: @yellow;
-        font-weight: 600;
-        &.select {
-          background-color: @yellow;
-          color: @blue;
-        }
-        &.disabled {
-          border-color: rgba(255, 255, 255, 0.2);
-          color: rgba(255, 255, 255, 0.2);
-          background-color: transparent;
-        }
-        &.out {
-          position: relative;
-          &::before {
-            content: ' ';
-            position: absolute;
-            width: 8px;
-            height: 100%;
-            background-color: @red;
-            transform-origin: 50% 58%;
-            transform: rotateZ(45deg);
-          }
-          &::after {
-            content: ' ';
-            position: absolute;
-            width: 8px;
-            height: 100%;
-            background-color: @red;
-            transform-origin: 0 70%;
-            transform: rotateZ(-45deg);
-          }
-        }
-      }
-    }
-    .operate {
-      display: flex;
-      justify-content: space-around;
-      padding-top: 40px;
-      .btn {
-        width: 140px;
-        height: 50px;
-        font-size: 26px;
-        border-radius: 6px;
-        border: none;
-      }
-      .forget {
-        color: @text;
-        background-color: @yellow;
-      }
-      .vote {
-        color: @text;
-        background-color: @red;
-      }
-    }
-    .mask {
-      position: fixed;
-      top: 0;
-      left: 0;
-      width: 100vw;
-      height: 100vh;
-      display: flex;
-      justify-content: center;
-      align-items: center;
-      background-color: rgba(0, 0, 0, 0.6);
-      .forget-cards {
-        width: 200px;
-        height: 300px;
-        background-color: @yellow;
-        text-align: center;
-        .number {
-          font-size: 32px;
-          padding-top: 50px;
-        }
-        .word {
-          font-size: 36px;
-          padding-top: 40px;
-        }
-      }
-    }
   }
 </style>

+ 6 - 0
src/types/index.d.ts

@@ -4,3 +4,9 @@ declare interface InterFaceUserInfo {
   job: string;
   auth: string[];
 }
+declare interface InterfacePlayer {
+  num: number;
+  text: string;
+  status: number;
+  identity: number;
+}

+ 5 - 0
src/utils/enum.ts

@@ -0,0 +1,5 @@
+export enum EnumIdentity {
+  civilian = 1,
+  spy = 2,
+  white = 3
+}

+ 1 - 1
src/utils/storage.ts

@@ -1,5 +1,5 @@
 import { SESSION_KEY } from './constant';
-interface InterfaceInitSession {
+export interface InterfaceInitSession {
   player: number;
   spy: number;
   white: number;

+ 13 - 0
src/utils/tools.ts

@@ -0,0 +1,13 @@
+// 生成随机数组
+export const randomPlayer = (sum: number, num: number, exist: number[] = []): number[] => {
+  const arr: number[] = [];
+  for (let i = 0; i < num; i++) {
+    const r = Math.floor(Math.random() * sum);
+    if (arr.includes(r) || exist.includes(r)) {
+      i--;
+    } else {
+      arr.push(r);
+    }
+  }
+  return arr;
+};