فهرست منبع

聊天室添加语音插件

dinghui 4 سال پیش
والد
کامیت
fb11398fbe
2فایلهای تغییر یافته به همراه241 افزوده شده و 5 حذف شده
  1. 202 0
      src/apps/mobile/components/ImAudio/index.vue
  2. 39 5
      src/apps/mobile/views/monitoring-center-bank/chat-room/chat-room.vue

+ 202 - 0
src/apps/mobile/components/ImAudio/index.vue

@@ -0,0 +1,202 @@
+<template>
+    <div class="x-audio-wrap" :class="{inline:!block}" ref="wrap" @click="play">
+        <div class="x-sector" :class="{play:animate}">
+            <div class="x-dot"></div>
+        </div>
+        <div class="x-time">{{duration&&showDuration?duration:text}}</div>
+    </div>
+</template>
+<script>
+export default {
+    name: 'im-audio',
+    props: {
+        src: {
+            type: String,
+            default: '',
+        },
+        text: {
+            type: String,
+            default: '轻触播放',
+        },
+        showDuration: {
+            type: Boolean,
+            default: true,
+        },
+        block: {
+            type: Boolean,
+            default: false,
+        },
+    },
+    data() {
+        return {
+            audio: null,
+            animate: false,
+            timer: null,
+            duration: null,
+        };
+    },
+    mounted() {
+        this.audio = new Audio();
+        this.audio.src = this.src;
+        this.audio.addEventListener('canplaythrough', () => {
+            this.duration = this.format(this.audio.duration);
+        });
+        this.audio.onplay = () => {
+            this.animate = true;
+            this.timer = setInterval(() => {
+                this.animate = false;
+                setTimeout(() => {
+                    this.animate = true;
+                }, 50);
+            }, 1250);
+        };
+        this.audio.onpause = () => {
+            this.animate = false;
+            this.timer && clearInterval(this.timer);
+        };
+        this.audio.onended = () => {
+            this.animate = false;
+            this.timer && clearInterval(this.timer);
+        };
+        if(!window.audioList) {
+            window.audioList = []
+        }
+        window.audioList.push(this.audio); //所有实例加入全局变量
+    },
+    methods: {
+        play() {
+            window.audioList.forEach((audio) => {
+                //开始前先关闭所有可能正在运行的实例
+                audio.pause();
+            });
+            if (this.audio.paused) {
+                this.audio.play();
+            } else {
+                this.audio.pause();
+            }
+        },
+        format(s) {
+            var t = '';
+            if (s > -1) {
+                var min = Math.floor(s / 60) % 60;
+                var sec = s % 60;
+                if (min < 10) {
+                    t += '0';
+                }
+                t += min + "'";
+                if (sec < 10) {
+                    t += '0';
+                }
+                t += sec.toFixed(2);
+            }
+            t = t.replace('.', '"');
+            return t;
+        },
+    },
+};
+</script>
+<style lang="stylus" scoped>
+.x-audio-wrap {
+    height: 30px;
+    width: 110px;
+    border-radius: 15px;
+    // border: 1px solid #ddd;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    cursor: pointer;
+    box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.25);
+
+    .x-sector {
+        height: 7px;
+        width: 7px;
+        border-radius: 4px 10px;
+        border-right: 2px solid #ddd;
+        border-top: 2px solid #ddd;
+        transform: rotate(45deg);
+        position: relative;
+        margin-left: 10px;
+
+        .x-dot {
+            height: 4px;
+            width: 4px;
+            border-radius: 4px;
+            background: #ddd;
+            position: absolute;
+            top: 4px;
+        }
+    }
+
+    .x-sector::before {
+        content: '';
+        height: 9px;
+        width: 9px;
+        border-radius: 4px 12px;
+        border-right: 2px solid #ddd;
+        border-top: 2px solid #ddd;
+        transform: rotate(0deg);
+        position: absolute;
+        right: -7px;
+        top: -7px;
+    }
+
+    .x-sector::after {
+        content: '';
+        height: 12px;
+        width: 12px;
+        border-radius: 4px 14px;
+        border-right: 2px solid #ddd;
+        border-top: 2px solid #ddd;
+        transform: rotate(0deg);
+        position: absolute;
+        right: -13px;
+        top: -13px;
+    }
+
+    .x-time {
+        color: #999;
+        font-size: 12px;
+        margin-right: 10px;
+    }
+
+    &.inline {
+        display: inline-flex;
+    }
+}
+
+@keyframes play-dot {
+    from {
+        background: #ddd;
+    }
+
+    to {
+        background: #5cadff;
+    }
+}
+
+@keyframes play-sector {
+    from {
+        border-color: #ddd;
+    }
+
+    to {
+        border-color: #5cadff;
+    }
+}
+
+.x-sector.play {
+    animation: play-sector 0.3s 0.1s ease-in-out;
+}
+
+.x-sector.play::before {
+    animation: play-sector 0.3s 0.2s ease-in-out;
+}
+
+.x-sector.play::after {
+    animation: play-sector 0.3s 0.3s ease-in-out;
+}
+
+.x-sector.play .x-dot {
+    animation: play-dot 0.3s ease-in-out;
+}
+</style>

+ 39 - 5
src/apps/mobile/views/monitoring-center-bank/chat-room/chat-room.vue

@@ -45,12 +45,18 @@
                                         fit="cover"
                                     ></el-image>
                                 </div>
-                                <div class="chat-records-content" v-if="(item.msg.substr(item.msg.lastIndexOf('.')+1)!='jpg') && (item.msg.substr(item.msg.lastIndexOf('.')+1)!='png')">{{item.msg}}</div>                                
-                                <div class="chat-records-content" v-else>
-                                    <span @click="imgOpen(item.msg)" style="cursor:pointer;">
-                                        <el-image :src="item.msg | pathPipe" style="width:100px;height:100px;">
+                                <div class="chat-records-content" v-if="checkMsgType(item.msg) === 'text'">{{item.msg}}</div>                                
+                                <div class="chat-records-content" v-if="checkMsgType(item.msg) === 'img'">
+                                    <!-- <span @click="imgOpen(item.msg)" style="cursor:pointer;"></span> -->
+                                        <el-image 
+                                        :src="item.msg | pathPipe" 
+                                        style="width:100px;height:100px;"
+                                        :preview-src-list="[item.msg]">
                                         </el-image>
-                                    </span>
+                                    
+                                </div>
+                                <div class="chat-records-content" v-if="checkMsgType(item.msg) === 'sound'">
+                                    <im-audio :src="item.msg"></im-audio>
                                 </div>
                             </div>
                         </div>
@@ -184,7 +190,11 @@ import { webSocketUrl } from '../../../../../config';
 import { queryLiftCasesList, queryChatHistoryList, invitationExpert, queryMsgHistoryList } from '@/apps/mobile/api/monitoring-center/index';
 import { queryAllExpert } from '@/apps/mobile/api/expert/index';
 import { isArray, chatUnique, chatUnique2 } from '@/apps//mobile/utils/util';
+import ImAudio from '@/apps/mobile/components/ImAudio'
 export default {
+    components: {
+        ImAudio
+    },
     data() {
         return {
             id: null, // 诊单id
@@ -499,6 +509,19 @@ export default {
             obj.sessionid = this.sessionId;
             obj.userId = this.customerServiceId;
             this.$ws.send(JSON.stringify(obj));
+        },
+        checkMsgType(str) {
+            let strPostfix = str.substring(str.lastIndexOf('.'))
+            strPostfix = strPostfix.toLowerCase();
+            let imgFilter = ['.jpeg', '.jpg', '.png', '.gif']
+            let soundFilter = ['.aac', '.mp3']
+            if(imgFilter.indexOf(strPostfix) !== -1) {
+                return 'img'
+            } else if(soundFilter.indexOf(strPostfix) !== -1) {
+                return 'sound'
+            } else {
+                return 'text'
+            }
         }
     },
     destroyed() {
@@ -646,6 +669,17 @@ export default {
                 .reverse {
                     flex-direction: row-reverse;
                 }
+
+                ::v-deep .el-image{
+                    img{
+                        pointer-events: auto;
+                    }
+
+                    .el-icon-circle-close {
+                        font-size: 50px;
+                        color: #fff;
+                    }
+                }
             }
         }