gemercheung 2 năm trước cách đây
mục cha
commit
f8895d57b6

+ 94 - 0
src/components/chatRoom/dialog/checkBrowser.vue

@@ -0,0 +1,94 @@
+<template>
+  <div id="checkBrowser">
+    <i class="iconfont iconshow_cancel" @click="closeCheckBrowser"></i>
+    <p class="title">建議使用以下最新版本的瀏覽器用於通話</p>
+    <div class="browser_list">
+      <div class="item" v-for="i,index in browserList" :key="index">
+        <div class="browser_icon">
+          <img :src="$config.getStaticResource(`img/apps/rtcLive/${i.icon}.png`)" alt="">
+        </div>
+        <div class="browser_name">{{i.name}}</div>
+        <!-- <div class="browser_version ">{{i.version}}</div> -->
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+export default {
+  data() {
+    return {
+      browserList: [
+        {
+          icon: "chrome",
+          name: "Chrome",
+          version: "60",
+        },
+        {
+          icon: "firefox",
+          name: "Firefox",
+          version: "55",
+        },
+        {
+          icon: "edge",
+          name: "Edge",
+          version: "40",
+        },
+        {
+          icon: "safari",
+          name: "Safari",
+          version: "11",
+        },
+      ],
+    };
+  },
+  components: {},
+  methods: {
+    closeCheckBrowser() {
+      this.$parent.showCheckBrowser = false;
+    },
+  },
+};
+</script>
+
+<style scoped lang="scss">
+#checkBrowser {
+  position: fixed;
+
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  z-index: 1000;
+  background: rgba(0, 0, 0, 0.5);
+  padding: 1.11rem;
+  border-radius: 0.14rem;
+  text-align: center;
+  z-index: 10000;
+  .iconshow_cancel {
+    font-size: 0.42rem;
+    position: absolute;
+    right: 0.33rem;
+    top: 0.33rem;
+  }
+  .title {
+    font-size: 0.28rem;
+    color: #fff;
+  }
+  .browser_list {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin: 0.42rem 0 0 0;
+    .item {
+      img {
+        width: 1.39rem;
+        height: auto;
+      }
+      margin-right: 0.28rem;
+      &:last-of-type {
+        margin-right: 0;
+      }
+    }
+  }
+}
+</style>

+ 357 - 0
src/components/chatRoom/dialog/createdRoom.vue

@@ -0,0 +1,357 @@
+<template>
+  <div id="createdRoom" @click.stop>
+    <div class="created_dialog">
+      <div class="blurBox"></div>
+      <div class="content">
+        <div class="dialog_title" v-if="role == 'leader'">创建一起逛</div>
+        <div class="dialog_title" v-else>进入一起逛</div>
+        <div class="avatar-box" v-if="role == 'leader'" :style="`background-image:url(${avatar || defaultAvatar});`">
+          <input type="file" @change="changeFile($event)" accept=".jpg,.png" />
+          <div class="tips">更换</div>
+        </div>
+        <div class="user_name">
+          <input class="input_name" maxlength="20" v-model.trim="userName" type="text" :placeholder="role == 'leader' ? ' 请输入发起人昵称' : '请输入您的昵称'" />
+          <span class="limitNum">{{ userName.length }}/20</span>
+        </div>
+        <!-- <div v-if="role!='customer'" class="mode_btn">
+          <div @click="chooseMode(i.mode)" v-for="i,index in modeList" :key="index" :class="{ active: mode==i.mode }" class="mode">{{i.title}}</div>
+        </div> -->
+        <div class="created_btn">
+          <div class="created_cancel" @click="closeCreated">取消</div>
+          <div class="created_confirm" @click="createdConfirm">确认</div>
+        </div>
+      </div>
+    </div>
+    <Cropper v-bind="option" v-if="showCrop" @close="closeCrop" @ok="confirmCrop" />
+  </div>
+</template>
+
+<script lang="ts">
+import Dialog from '/@/components/basic/dialog';
+import browser from '/@/utils/browser';
+import { useStore } from 'vuex';
+import Cropper from '@/components/cropper/cropper.vue';
+export default {
+  data() {
+    return {
+      role: browser.getURLParam('role') || 'leader',
+      mode: browser.getURLParam('mode') || 2,
+      modeList: [
+        {
+          mode: 1,
+          title: '1V1',
+        },
+        {
+          mode: 2,
+          title: '多人模式',
+        },
+      ],
+      store: useStore(),
+      userName: '',
+      roomId: browser.getURLParam('roomId'),
+      showCrop: false,
+      // base64: null,
+      defaultAvatar: require('@/assets/images/avatar_default.png'),
+      // avatar: null,
+      option: {
+        // img: 'https://4dkk.4dage.com/scene_edit_data/KK-t-SfG2Xcb8QX/user/thumb-1k.jpg?_=1661768330305',
+        img: '',
+      },
+    };
+  },
+
+  mounted() {
+   
+  },
+  computed: {
+    avatar: function () {
+      return this.$store.getters['rtc/avatar']
+    },
+  },
+  components: { Cropper },
+  // created: {},
+  // mounted:{},
+  methods: {
+    changeFile(e) {
+      let file = e.target.files[0];
+
+      let blob = window.URL.createObjectURL(file);
+      console.log(blob);
+      this.option.img = blob;
+      this.openCrop();
+      e.target.value = '';
+    },
+    confirmCrop(base64) {
+      this.$store.commit('rtc/setAvatar', base64);
+    },
+    openCrop() {
+      this.showCrop = true;
+    },
+    closeCrop() {
+      this.showCrop = false;
+    },
+    getUrl(href, queryArr) {
+      queryArr.forEach((item) => {
+        if (!browser.hasURLParam(item.key)) {
+          let ttt = href.split('index.html?');
+          href = `${ttt[0]}index.html?${item.key}=${item.val}&${ttt[1]}`;
+        } else {
+          href = browser.replaceQueryString(href, item.key, item.val);
+        }
+      });
+
+      return href;
+    },
+
+    chooseMode(mode) {
+      this.mode = mode;
+    },
+    closeCreated() {
+      this.$emit('closeCreated');
+    },
+    createdConfirm() {
+      if (this.userName == '') {
+        Dialog.toast({ content: '请输入入您的昵称', type: 'error' });
+        return;
+      }
+      let name = encodeURIComponent(this.userName);
+      let hh = window.location.href;
+
+      if (this.role == 'customer') {
+        let tempUrl = this.getUrl(hh, [
+          {
+            key: 'mode',
+            val: this.mode,
+          },
+          {
+            key: 'name',
+            val: name,
+          },
+          {
+            key: 'role',
+            val: 'customer',
+          },
+          {
+            key: 'roomId',
+            val: this.roomId,
+          },
+        ]);
+        // history.replaceState(null, null, hh + "&mode=" + this.mode + "&name=" + name + "&role=customer&roomId=" + this.roomId);
+        history.replaceState(null, null, tempUrl);
+      } else {
+        let tempUrl = this.getUrl(hh, [
+          {
+            key: 'mode',
+            val: this.mode,
+          },
+          {
+            key: 'name',
+            val: name,
+          },
+          {
+            key: 'role',
+            val: 'leader',
+          },
+        ]);
+
+        // history.replaceState(null, null,hh + "&mode=" + this.mode + "&name=" + name + "&role=leader");
+        history.replaceState(null, null, tempUrl);
+        console.log(tempUrl);
+      }
+      this.store.commit('rtc/setRole', this.role);
+
+      this.$nextTick(() => {
+        this.$emit('createdConfirm');
+      });
+    },
+  },
+};
+</script>
+
+<style scoped lang="scss">
+#createdRoom {
+  width: 100vw;
+  height: 100%;
+  // background: rgba(0, 0, 0, 0.5);
+  background: transparent;
+  position: fixed;
+  left: 0;
+  top: 0;
+  z-index: 1000000;
+  // pointer-events: none;
+  .created_dialog {
+    width: 8.64rem;
+    min-height: 5rem;
+    // background: #ffffff;
+    pointer-events: auto;
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -50%);
+    // overflow: hidden;
+    border: 1px solid rgba(255, 255, 255, 0.1);
+    border-radius: 4px;
+
+    .blurBox {
+      position: absolute;
+      z-index: 1;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      background: rgba(0, 0, 0, 0.7);
+      filter: blur(1px);
+    }
+    .content {
+      position: relative;
+      z-index: 2;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+    }
+    .avatar-box {
+      width: 1.7067rem;
+      height: 1.7067rem;
+      margin: 0.56rem auto 0;
+      border: 1px #fff solid;
+      border-radius: 50%;
+      // background-image: url('@/assets/images/avatar_default.jpg');
+      background-size: 100%;
+      background-repeat: no-repeat;
+      position: relative;
+      overflow: hidden;
+      cursor: pointer;
+      &:hover {
+        border: 1px #ed5d18 solid;
+        .tips {
+          color: #ed5d18;
+        }
+      }
+      .tips {
+        width: 100%;
+        height: 0.5rem;
+        position: absolute;
+        background: rgba(0, 0, 0, 0.5);
+        bottom: 0;
+        left: 0;
+        text-align: center;
+        line-height: 0.5rem;
+        font-size: 0.22rem;
+      }
+      input {
+        width: 100%;
+        height: 100%;
+        opacity: 0;
+        position: relative;
+        z-index: 10;
+        cursor: pointer;
+      }
+    }
+    .dialog_title {
+      font-size: 0.39rem;
+      width: 100%;
+      height: 1.39rem;
+      padding: 0 0.56rem;
+      box-sizing: border-box;
+      font-size: 0.39rem;
+      color: #fff;
+      line-height: 1.39rem;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+      border-bottom-style: solid;
+      border-bottom-width: 1px;
+      border-bottom-color: rgba(255, 255, 255, 0.1);
+    }
+    .user_name {
+      width: 100%;
+      height: 1.11rem;
+      padding: 0 0.56rem;
+      box-sizing: border-box;
+      font-size: 0.39rem;
+      line-height: 1.11rem;
+      margin: 0.56rem 0;
+      position: relative;
+      .limitNum {
+        position: absolute;
+        right: 0.64rem;
+        top: 50%;
+        transform: translateY(-50%);
+        font-size: 0.33rem;
+        color: #b9bdbc;
+      }
+      .input_name {
+        font-size: 0.39rem;
+        width: 100%;
+        height: 100%;
+        line-height: 1.11rem;
+        padding: 0 1.066667rem 0 0.28rem;
+        box-sizing: border-box;
+        background: rgba(0, 0, 0, 0.5);
+        border-radius: 4px;
+        color: #fff;
+        border: none;
+        outline: none;
+        &::placeholder {
+          color: rgba(255, 255, 255, 0.3);
+        }
+      }
+    }
+    .mode_btn {
+      width: 100%;
+      height: 1.11rem;
+      padding: 0 0.56rem;
+      box-sizing: border-box;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      margin-bottom: 0.56rem;
+      > div.mode {
+        width: 3.61rem;
+        height: 100%;
+        border-radius: 0.65rem;
+        border: 0.03rem solid #fff;
+        color: #fff;
+        font-size: 0.39rem;
+        line-height: 1.11rem;
+        text-align: center;
+        box-sizing: border-box;
+        &.active {
+          color: #ed5d18;
+          border: 0.03rem solid #ed5d18;
+        }
+      }
+    }
+    .created_btn {
+      width: 100%;
+      height: 1.36rem;
+      border-top-style: solid;
+      border-top-width: 1px;
+      border-top-color: rgba(255, 255, 255, 0.1);
+      box-sizing: border-box;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      font-size: 0.39rem;
+      > div {
+        width: 50%;
+        height: 1.36rem;
+        text-align: center;
+        line-height: 1.36rem;
+        font-size: 0.39rem;
+        box-sizing: border-box;
+        &.created_cancel {
+          color: #fff;
+          border-right-style: solid;
+          border-right-width: 1px;
+          border-right-color: rgba(255, 255, 255, 0.1);
+        }
+        &.created_confirm {
+          color: #ed5d18;
+        }
+      }
+    }
+  }
+}
+</style>

+ 143 - 0
src/components/chatRoom/dialog/index.vue

@@ -0,0 +1,143 @@
+<template>
+  <div id="dialog_index">
+    <div class="created_dialog">
+      <div class="blurBox"></div>
+      <div class="content">
+        <div class="dialog_title">{{ props.title }}</div>
+        <p class="dialog_desc">{{ props.desc }}</p>
+        <div class="created_btn">
+          <div class="end_cancel" @click="endLiveCancel">取消</div>
+          <div class="end_confirm" @click="endLiveConfirm">立即结束</div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import browser from "@/utils/browser";
+import { onMounted, watch, defineProps, defineEmits, ref, computed } from "vue";
+import { useStore } from "vuex";
+const store = useStore();
+
+const emit = defineEmits(["closeDialog","confirmDialog"]);
+
+const role = ref(browser.urlHashValue("role"));
+const socket = computed(() => store.getters["rtc/socket"]);
+
+
+const props = defineProps({
+  title: {
+    type: String,
+    default: "温馨提示",
+  },
+  desc: {
+    type: String,
+    default: "是否结束带看?",
+  },
+});
+
+const endLiveCancel = () => {
+  emit("closeDialog");
+};
+
+const endLiveConfirm = () => {
+  // socket.value.emit("disconnect");
+  emit("confirmDialog");
+};
+</script>
+
+<style scoped lang="scss">
+#dialog_index {
+  width: 100vw;
+  height: 100%;
+  // background: rgba(0, 0, 0, 0.5);
+  position: fixed;
+  left: 0;
+  top: 0;
+  z-index: 100000;
+  pointer-events: none;
+  .created_dialog {
+    pointer-events: auto;
+    width: 8.64rem;
+    // min-height: 5rem;
+    // background: #ffffff;
+    border-radius: 8px;
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -50%);
+    border: 1px solid rgba(255, 255, 255, 0.1);
+    border-radius: 4px;
+    .blurBox {
+      position: absolute;
+      z-index: 1;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      background: rgba(0, 0, 0, 0.7);
+      filter: blur(1px);
+    }
+    .content {
+      position: relative;
+      z-index: 2;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+    }
+    .dialog_title {
+      width: 100%;
+      height: 1.39rem;
+      padding: 0 0.56rem;
+      box-sizing: border-box;
+      font-size: 0.39rem;
+      color: #fff;
+      line-height: 1.39rem;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+      border-bottom-style: solid;
+      border-bottom-width: 1px;
+      border-bottom-color: rgba(255, 255, 255, 0.1);
+    }
+    .dialog_desc {
+      font-size: 0.42rem;
+      color: #fff;
+      padding: 0.56rem 0;
+      text-align: center;
+    }
+
+    .created_btn {
+      width: 100%;
+      height: 1.36rem;
+      border-top-style: solid;
+      border-top-width: 1px;
+      border-top-color: rgba(255, 255, 255, 0.1);
+      box-sizing: border-box;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      font-size: 0.39rem;
+      > div {
+        width: 50%;
+        height: 1.36rem;
+        text-align: center;
+        line-height: 1.36rem;
+        font-size: 0.39rem;
+        box-sizing: border-box;
+        &.end_cancel {
+          color: #fff;
+          border-right-style: solid;
+          border-right-width: 1px;
+          border-right-color: rgba(255, 255, 255, 0.1);
+        }
+        &.end_confirm {
+          color: #ed5d18;
+        }
+      }
+    }
+  }
+}
+</style>

+ 169 - 0
src/components/chatRoom/dialog/share.vue

@@ -0,0 +1,169 @@
+<template>
+  <div id="dialog_index">
+    <div class="created_dialog">
+      <div class="blurBox"></div>
+      <div class="content">
+        <div class="dialog_title">{{ title }}</div>
+        <div class="dialog_link">
+          <p>
+            {{ shareLink }}
+          </p>
+        </div>
+
+        <div class="created_btn">
+          <div class="created_cancel" @click="closeCreated">取消</div>
+          <div class="created_confirm"  ref="copylink$" :data-clipboard-text="shareLink" @click="createdConfirm">复制分享</div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { onMounted, watch, defineProps, defineEmits, ref, nextTick } from "vue";
+import ClipboardJS from 'clipboard'
+import { Dialog } from '@/global_components/'
+
+const emit = defineEmits(["closeDialog"]);
+
+const props = defineProps({
+  title: {
+    type: String,
+    default: "邀请好友",
+  },
+  shareLink: {
+    type: String,
+    default: "",
+  },
+});
+const copylink$ = ref(null)
+
+const closeCreated = () => {
+  emit("closeDialog");
+};
+
+const createdConfirm = () => {
+  emit("closeDialog");
+};
+
+onMounted(() => {
+   nextTick(()=>{
+     new ClipboardJS(copylink$.value).on('success', function (e) {
+        e.clearSelection()
+        Dialog.toast({ content: '链接复制成功', type: 'success' })
+    })
+   })
+})
+
+</script>
+
+<style scoped lang="scss">
+#dialog_index {
+  width: 100vw;
+  height: 100%;
+  // background: rgba(0, 0, 0, 0.5);
+  position: fixed;
+  left: 0;
+  top: 0;
+  z-index: 100000;
+  pointer-events: none;
+  .created_dialog {
+    width: 8.64rem;
+    // min-height: 5rem;
+    // background: #ffffff;
+    border-radius: 8px;
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -50%);
+    pointer-events: auto;
+    border: 1px solid rgba(255, 255, 255, 0.1);
+    border-radius: 4px;
+    .blurBox {
+      position: absolute;
+      z-index: 1;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      background: rgba(0, 0, 0, 0.7);
+      filter: blur(1px);
+    }
+    .content {
+      position: relative;
+      z-index: 2;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+    }
+    .dialog_title {
+      width: 100%;
+      height: 1.39rem;
+      padding: 0 0.56rem;
+      box-sizing: border-box;
+      font-size: 0.39rem;
+      color: #fff;
+      line-height: 1.39rem;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+      border-bottom-style: solid;
+      border-bottom-width: 1px;
+      border-bottom-color: rgba(255, 255, 255, 0.1);
+    }
+    .dialog_link {
+      width: 100%;
+      font-size: 0.39rem;
+      color: rgba(255, 255, 255, 0.5);
+      padding: 0.53rem 0.56rem;
+      box-sizing: border-box;
+      text-align: justify;
+      text-align: left;
+      > p {
+        background: rgba(0, 0, 0, 0.5);
+        padding: 0.15rem 0.28rem;
+        word-break: break-all;
+        word-wrap: break-word;
+        text-overflow: -o-ellipsis-lastline;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        display: -webkit-box;
+        -webkit-line-clamp: 2;
+        line-clamp: 2;
+        -webkit-box-orient: vertical;
+        line-height: 0.72rem;
+      }
+    }
+
+    .created_btn {
+      width: 100%;
+      height: 1.36rem;
+      border-top-style: solid;
+      border-top-width: 1px;
+      border-top-color: rgba(255, 255, 255, 0.1);
+      box-sizing: border-box;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      > div {
+        width: 50%;
+        height: 1.36rem;
+        text-align: center;
+        line-height: 1.36rem;
+        font-size: 0.39rem;
+        box-sizing: border-box;
+        &.created_cancel {
+          color: #fff;
+          border-right-style: solid;
+          border-right-width: 1px;
+          border-right-color: rgba(0, 0, 0, 0.05);
+        }
+        &.created_confirm {
+          color: #ed5d18;
+        }
+      }
+    }
+  }
+}
+</style>

+ 2 - 2
src/components/chatRoom/memberList.vue

@@ -12,7 +12,7 @@
             <div class="userMsg">
               <div class="avatar" :class="`${role}`">
                 <img
-                  :src="i?.Avatar || require('@/assets/images/rtcLive/avatar_small@2x.png')"
+                  :src="i?.Avatar || defaultAvatar"
                   alt=""
                 />
                 <div class="avatar-crown" v-show="i.Role === 'leader'"></div>
@@ -52,7 +52,7 @@
 <script lang="ts" setup>
   import { propTypes } from '/@/utils/propTypes';
   import { UserInfoType, useRtcStore } from '/@/store/modules/rtc';
-  // import avatarSmall from "/@/assets/images/rtcLive/avatar_small@2x.png";
+  import defaultAvatar from "/@/assets/images/rtcLive/avatar_small@2x.png";
   import { computed, watchEffect } from 'vue';
   import { useSocket } from '/@/hooks/userSocket';
   const rtcStore = useRtcStore();

+ 3 - 0
src/hooks/userSocket.ts

@@ -1,3 +1,4 @@
+import { useAppStore } from '../store/modules/app';
 import { getApp } from './userApp';
 import { useRoom } from './useRoom';
 import { useRtcStore } from '/@/store/modules/rtc';
@@ -26,8 +27,10 @@ export function createSocket() {
 async function closeSocket() {
   const { leaveRoom } = useRoom();
   const rtcStore = useRtcStore();
+  const appStore = useAppStore();
   await getApp().Connect.follow.exit();
   await leaveRoom();
+  appStore.setIsTourMode(true)
   if (rtcStore.isLeader) {
     socket.emit('action', { type: 'leader-dismiss' });
   }