gemercheung 2 лет назад
Родитель
Сommit
4584185ffe

+ 12 - 10
src/components/chatRoom/chat.vue

@@ -1,13 +1,15 @@
 <template>
   <div id="chat">
     <div id="contents">
-      <div class="chat-item" v-for="(i, index) in chatList" :key="index">
+      <div class="chat-item flex" v-for="(i, index) in chatList" :key="index">
         <div class="chat-msg">
           <!-- {{ user_info }} -->
           <!-- <span :class="{ my: i.UserId == user_info.UserId }" class="chat-name">
             {{ i.Nickname }} &nbsp;
           </span> -->
-          <span class="chat-name"> {{ i.Nickname }} &nbsp; </span>
+          <span class="chat-name" :class="{ my: isMe(i.UserId) }">
+            {{ i.Nickname }} &nbsp;
+          </span>
           <span class="chat-content"> {{ i.text }}</span>
         </div>
       </div>
@@ -18,20 +20,20 @@
 <script setup lang="ts">
 // import { propTypes } from "/@/utils/propTypes";
 
+import { computed } from "vue";
 import { ChatContentType } from "/@/store/modules/rtc";
-
-// import { defineProps } from "vue";
-defineProps({
-  user_info: {
-    // type: Object,
-    type: Object as PropType<ChatContentType>,
-    default: () => {},
-  },
+import { propTypes } from "/@/utils/propTypes";
+const props = defineProps({
+  currentUser: propTypes.string.def(""),
   chatList: {
     type: Array as PropType<ChatContentType[]>,
     default: () => [],
   },
 });
+
+const isMe = computed(
+  () => (currentUser: string) => props.currentUser === currentUser
+);
 </script>
 
 <style scoped lang="scss">

+ 13 - 5
src/components/chatRoom/controls/actions.ts

@@ -1,23 +1,25 @@
-import { useRtcStore } from "/@/store/modules/rtc";
+import { UserInfoType, useRtcStore } from "/@/store/modules/rtc";
 import type { ChatContentType } from "/@/store/modules/rtc";
 
 interface ActionDataType {
     type: string;
-    data: any
+    data: any,
+    members?: UserInfoType[]
 }
 
-export function handleActions(data: ActionDataType) {
-    switch (data.type) {
+export function handleActions({ data, type, members }: ActionDataType) {
+    switch (type) {
         case 'user-init':
             break;
         case 'danmumsg':
-            handleDanMumSg(data.data)
+            handleDanMumSg(data)
             break;
 
         case "changeScene":
             break;
 
         case 'user-join':
+            handleUserJoin(members)
             break;
         case "user-leave":
             break;
@@ -52,4 +54,10 @@ function handleDanMumSg(data: ChatContentType) {
         data.Nickname = "主持人";
     }
     rtcStore.addToChatList(data)
+}
+// 
+function handleUserJoin(members: UserInfoType[]) {
+    const rtcStore = useRtcStore();
+    debugger
+    rtcStore.setMemberList(members)
 }

+ 0 - 1
src/components/chatRoom/controls/paint.ts

@@ -8,5 +8,4 @@ export function handlePaint(data: any) {
     if (!rtcStore.isLeader) {
         app.Connect.paint.receive(data);
     }
-
 }

+ 87 - 16
src/components/chatRoom/index.vue

@@ -1,8 +1,11 @@
 <template>
   <!-- 主区域 start  -->
   <div id="PageRtcLive">
-    <chat v-show="true" :chatList="chatList"></chat>
-
+    <chat
+      v-show="chatShow"
+      :chatList="chatList"
+      :currentUser="currentUser"
+    ></chat>
     <!-- 控制条 start -->
     <div class="controlBar" v-if="!showInput">
       <div class="saySomething" @click="onFocus">
@@ -11,19 +14,31 @@
         <span>说点什么~</span>
         <!-- <span>已被禁言</span> -->
 
-        <div class="disSpeakBtn"></div>
+        <div
+          class="disSpeakBtn"
+          @click.stop="chatShow = !chatShow"
+          :class="{ dis: !chatShow }"
+        ></div>
       </div>
       <!-- <div style="text-align: right; width: 100%">连接中...</div> -->
       <div class="control_btn">
-        <div class="brushesBack"></div>
-        <div class="brushes"></div>
+        <div
+          class="brushesBack"
+          @click="onDrawUndo"
+          v-if="unref(isBrushes) && isNativeLeader"
+        ></div>
+        <div
+          class="brushes"
+          v-if="isNativeLeader"
+          @click="onDraw(!isBrushes)"
+        ></div>
 
         <div class="invitation"></div>
+        <!-- @click="openMember" -->
         <div v-if="isNativeLeader" class="members" @click="openMember"></div>
-        <template>
-          <div class="mic_on"></div>
-          <div class="mic_no"></div>
-          leader
+        <template v-if="isNativeLeader">
+          <div class="mic_on" v-if="unref(disableMic)"></div>
+          <div class="mic_no" v-if="!unref(disableMic)"></div>
         </template>
 
         <!-- <div style="font-size: 0.65rem">
@@ -55,26 +70,43 @@
       </div>
     </div>
     <!-- 输入框 end-->
+    <!-- 用户列表 start -->
+    <memberList
+      :data="[]"
+      :show="showMember"
+      :animateActive="animateActive"
+      @close-member="closeMember"
+    />
+    <!-- 用户列表 end -->
   </div>
 </template>
 
 <script lang="ts" setup>
-import { computed, nextTick, onMounted, ref } from "vue";
-import { getApp } from "/@/hooks/userApp";
+import { computed, nextTick, onMounted, ref, unref } from "vue";
+import { getApp, useApp } from "/@/hooks/userApp";
 import { initSocketEvent } from "./roomControl";
 import { createSocket } from "/@/hooks/userSocket";
 import browser from "/@/utils/browser";
 import { useRtcStore } from "/@/store/modules/rtc";
 import type { SocketParams, RoleType } from "/@/store/modules/rtc";
 import chat from "./chat.vue";
+import memberList from "./memberList.vue";
 import consola from "consola";
 
 const rtcStore = useRtcStore();
 const isNativeLeader = computed(() => rtcStore.role == "leader");
 const showInput = ref(false);
+const chatShow = ref(true);
+const isBrushes = ref(false);
+const canUndo = ref(false);
+const animateActive = ref(false);
+const showMember = ref(false);
+const disableMic = ref(false);
+const role = computed(() => rtcStore.role);
 const text = ref<string>("");
 const chatList = computed(() => rtcStore.chatList);
-const userInfo = computed(() => rtcStore.chatList);
+const currentUser = computed(() => rtcStore.userId);
+
 //设置socket 参数
 const initParams: SocketParams = {
   userId:
@@ -99,11 +131,40 @@ rtcStore.setSocketParams(initParams);
 const socket = createSocket();
 initSocketEvent(socket);
 
-onMounted(() => {
-  const app = getApp();
-});
+// onMounted(() => {
+//   const app = getApp();
+// });
 
 /* method */
+const onDrawUndo = async () => {
+  let app = getApp();
+  app.Connect.paint.undo();
+  canUndo.value = app.Connect.paint.records.length > 0;
+
+  console.log(app.Connect.paint.records, "app.Connect.paint.records");
+};
+
+const onDraw = async (status) => {
+  isBrushes.value = status;
+
+  if (unref(isBrushes)) {
+    const app = await useApp();
+    app.Connect.paint.show({
+      role: unref(role),
+      paint: isNativeLeader ? true : false,
+    });
+    if (unref(role) == "leader") {
+      socket.emit("action", { type: "user-paint", open: true });
+    }
+  } else {
+    const app = await useApp();
+    app.Connect.paint.hide();
+    if (unref(role) == "leader") {
+      socket.emit("action", { type: "user-paint", open: false });
+    }
+  }
+};
+
 function closeText(): void {
   showInput.value = false;
   text.value = "";
@@ -138,7 +199,17 @@ function onFocus(): void {
     document.getElementById("input_msg")?.focus();
   });
 }
-function openMember(): void {}
+const openMember = () => {
+  showMember.value = true;
+  animateActive.value = true;
+};
+const closeMember = () => {
+  animateActive.value = false;
+  let t = setTimeout(() => {
+    clearTimeout(t);
+    showMember.value = false;
+  }, 200);
+};
 </script>
 
 <style scoped lang="scss">

+ 102 - 0
src/components/chatRoom/memberList.vue

@@ -0,0 +1,102 @@
+<template>
+  <div class="layer" v-if="show" @click.self="closeMember">
+    <div
+      class="memberContent animated"
+      :class="animateActive ? 'fadeInUpBig' : 'fadeOutDownBig'"
+    >
+      <div class="blurBox"></div>
+      <div class="content">
+        <div class="memberHeader">
+          <span> 成员管理({{ data?.length }})</span>
+          <i class="iconfont"></i>
+        </div>
+        <div class="memberList">
+          <div class="memberItem">
+            <div class="userMsg">
+              <div class="avatar">
+                <img :src="currentListUser?.Avatar || avatarSmall" alt="" />
+              </div>
+              <div class="name" v-if="currentListUser?.Role == 'leader'">
+                {{ currentListUser?.Nickname }} (主持人,我)
+              </div>
+              <div class="name" v-else>
+                {{ currentListUser?.Nickname }} (我)
+              </div>
+            </div>
+
+            <!-- <div class="button" v-if="user_info.Role == 'leader'">
+                <div
+                  @click="setAllMuted(!all_mute_mic)"
+                  class="micBtn mute_all_mic"
+                  :class="{ open_all_mic: all_mute_mic }"
+                ></div>
+              </div> -->
+          </div>
+
+          <div
+            v-show="currentListUser?.UserId != i.UserId && i.Role != 'leader'"
+            class="memberItem"
+            v-for="(i, idx) in data"
+            :key="idx"
+          >
+            <div class="userMsg">
+              <div class="avatar">
+                <img
+                  :src="
+                    i?.Avatar ||
+                    require('@/assets/images/rtcLive/avatar_small@2x.png')
+                  "
+                  alt=""
+                />
+              </div>
+              <div class="name">{{ i.Nickname }}</div>
+            </div>
+            <div class="button" v-if="currentListUser?.Role == 'leader'">
+              <div
+                class="micBtn"
+                :class="i.IsWords ? 'ban_speak_on' : 'ban_speak_off'"
+                :wo="i.IsWords"
+                @click="userCanSpeak(i)"
+              ></div>
+              <!-- <div
+                  class="micBtn"
+                  :class="i.IsMuted ? 'mute_one_mic_off' : 'mute_one_mic_on'"
+                  @click="onMemberMuted(i)"
+                ></div> -->
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { propTypes } from "/@/utils/propTypes";
+import { UserInfoType } from "/@/store/modules/rtc";
+import avatarSmall from "/@/assets/images/rtcLive/avatar_small@2x.png";
+
+// const animateActive = ref(false);
+defineProps({
+  show: propTypes.bool.def(false),
+  animateActive: propTypes.bool.def(false),
+  data: {
+    type: Array as PropType<UserInfoType[]>,
+    default: () => [],
+  },
+  currentListUser: {
+    type: Object as PropType<UserInfoType>,
+    default: () => {},
+  },
+});
+const emit = defineEmits(["openMember", "closeMember"]);
+
+function closeMember(): void {
+  emit("closeMember");
+}
+function userCanSpeak() {}
+</script>
+
+<style lang="scss">
+@import "./chatroom.scss";
+</style>

+ 41 - 5
src/store/modules/rtc.ts

@@ -1,4 +1,5 @@
 import { defineStore } from 'pinia';
+import consola from 'consola'
 interface RtcState {
     socket: Nullable<SocketIOClient.Socket>,
     showDaoGou: boolean,
@@ -21,7 +22,8 @@ interface RtcState {
     avatar: Nullable<string>,
     nickname: Nullable<string>,
     mode: string,
-    chatList: ChatContentType[]
+    chatList: ChatContentType[],
+    memberList: UserInfoType[]
 }
 
 interface DeviceListParams {
@@ -38,8 +40,18 @@ export interface ChatContentType {
 }
 
 export interface UserInfoType {
-    UserId: string,
-    text: string,
+    Avatar: string
+    Id: string
+    InTime: string
+    IsClient: string
+    IsMuted: string
+    IsWords: string
+    JoinTime: string
+    Nickname: string
+    Role: string
+    RoomId: string
+    UserId: string
+    text?: string
 }
 export type RoleType = 'leader' | 'customer'
 export interface SocketParams {
@@ -52,6 +64,7 @@ export interface SocketParams {
 }
 
 
+
 export const useRtcStore = defineStore({
     id: 'rtc',
     state: (): RtcState => ({
@@ -76,11 +89,15 @@ export const useRtcStore = defineStore({
         invitedRemoteStreams: [],
         avatar: null,
         mode: '',
-        chatList: []
+        chatList: [],
+        memberList: []
     }),
     getters: {
         isLeader(): boolean {
             return this.role === 'leader'
+        },
+        isMe() {
+            return (userId: string) => this.userId === userId
         }
     },
     actions: {
@@ -90,6 +107,15 @@ export const useRtcStore = defineStore({
             this.userId = params.userId
             this.nickname = params.nickname
             this.role = params.role
+            if (!['leader', 'customer'].includes(params.role)) {
+                consola.info({
+                    message: '角色参数有误',
+                    level: 0,
+                    tag: 'role'
+                })
+                this.role = 'customer'
+
+            }
         },
         setAvatar(payload: string) {
             this.avatar = payload
@@ -132,9 +158,19 @@ export const useRtcStore = defineStore({
         setIsPublished(payload: boolean) {
             this.isPublished = payload
         },
-    
+
         addToChatList(content: ChatContentType) {
             this.chatList.push(content)
+        },
+        setMemberList(members: UserInfoType[]) {
+            const memberList = members.reduce(function (prev: UserInfoType[], current: UserInfoType) {
+                if (prev.findIndex((ele: UserInfoType) => ele.UserId === current.UserId) === -1) {
+                    console.log(current);
+                    prev.push(current);
+                }
+                return prev;
+            }, []);
+            this.memberList = memberList
         }
     }