Selaa lähdekoodia

0817-0219-h02

Zory 1 kuukausi sitten
vanhempi
sitoutus
321150eefb

+ 8 - 0
src/components/imFloat/imFloat.vue

@@ -907,6 +907,14 @@ export default {
 		onSetText(text) {},
         // 切换聊天窗口
         async toggleChat() {
+            const { href } = this.$router.resolve({
+                path: '/chat/web',      // 路径
+                query: { tab: 'chat' } // 参数(可选)
+                // 或者使用 name: 'Dashboard' 命名路由
+            });
+            const windowName = 'chatWeb';
+            window.open(href, windowName);
+            return ;
             this.visible = !this.visible
             if (this.visible) {
                 // 打开窗口时清除未读角标

+ 7 - 0
src/router/systemRouter.js

@@ -40,6 +40,13 @@ const routes = [
 			title: "重置密码"
 		}
 	},
+	{
+		path: "/chat/web",
+		component: () => import(/* webpackChunkName: "resetPassword" */ '@/views/service/chat/web'),
+		meta: {
+			title: "客服"
+		}
+	},
 	{
 		path: "/result",
 		component: () => import(/* webpackChunkName: "resetPassword" */ '@/views/login/result'),

+ 212 - 0
src/views/service/chat/components/aside.vue

@@ -0,0 +1,212 @@
+<template>
+    <div class="aside-user">
+        <div class="user-info">
+            <div class="avatar"><img src="https://washmy.oss-cn-guangzhou.aliyuncs.com/storage/20260713/3f8a9da46c4c8e503e75f2cca4d8c172bdb7de97.jpg" /></div>
+            <div class="info">
+                <div class="name">{{ userInfo.truename }}</div>
+                <div class="status">
+                    <el-dropdown trigger="click" @command="handleUser">
+                        <div class="user-state">
+                            <div class="names"><text class="success"></text>在线</div>
+                            <el-icon class="el-icon--right"><el-icon-arrow-down /></el-icon>
+                        </div>
+                        <template #dropdown>
+                            <el-dropdown-menu>
+                                <el-dropdown-item command="clearmenu">
+                                    <div class="state-item">
+                                        <div class="name"><text class="success"></text>在线</div>
+                                        <div class="desc">可接待所有客户咨询</div>
+                                    </div>
+                                </el-dropdown-item>
+                                <el-dropdown-item divided command="clearmenu">
+                                    <div class="state-item">
+                                        <div class="name"><text class="info"></text>离线</div>
+                                        <div class="desc">无法接收和发送消息</div>
+                                    </div>
+                                </el-dropdown-item>
+                            </el-dropdown-menu>
+                        </template>
+                    </el-dropdown>
+                </div>
+            </div>
+        </div>
+        <div class="sub-fitter">
+            <div class="search">
+                <div class="icon"><el-icon><el-icon-search /></el-icon></div>
+                <div class="info">用户昵称/聊天记录/订单号</div>
+            </div>
+            <div class="chat-tab">
+                <div class="chat-item-tab active">当前咨询</div>
+                <div class="chat-item-tab">历史咨询</div>
+            </div>
+        </div>
+        <div class="infinite-list-wrapper" style="overflow: auto">
+            <div>
+                <div class="chat-loading-sk" v-for="(item,indx) in 20" v-if="userLoading">
+                    <el-skeleton :animated="true">
+                        <template #template>
+                            <div class="chat-sk-flex">
+                                <el-skeleton-item variant="image" style="width: 40px; height: 40px" />
+                                <div class="sk-right">
+                                    <el-skeleton-item variant="h3" style="width: 50%" />
+                                    <div style="margin-top: 5px;">
+                                        <el-skeleton-item variant="text" style="width: 30%;" />
+                                    </div>
+                                </div>
+                                <div class="time">
+                                    <el-skeleton-item variant="text" />
+                                </div>
+                            </div>
+                        </template>
+                    </el-skeleton>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    data () {
+        return {
+            userLoading:true
+        }
+    },
+    props: {
+        userInfo: { type: Object, default: () => {} }
+    },
+    methods: {
+
+    }
+}
+</script>
+<style scoped>
+.aside-user{
+    display: flex;
+    flex-direction: column;
+    position: fixed;
+    z-index: 1;
+    top: 0;
+    left: 0;
+    bottom: 0;
+    right: 0;
+    width: 300px;
+    .infinite-list-wrapper{
+        flex: 1;
+    }
+}
+.chat-sk-flex{
+    display: flex;align-items: center;gap: 10px;padding: 10px;flex: 1;border-bottom: 1px solid #f8f8f8;
+    .sk-right{flex: 1;}
+    .time{margin-left: auto;margin-right: 0;width: 20px;}
+}
+.sub-fitter{
+    margin: 10px;
+    .search{
+        display: flex;
+        align-items: center;
+        height: 40px;
+        border: 1px solid var(--el-border-color-light);
+        padding: 0 10px;
+        border-radius: 5px;
+        gap: 10px;
+        cursor: pointer;
+        .info {
+            flex: 1;
+            color: #999;
+        }
+    }
+    .chat-tab{
+        margin-top: 10px;
+        display: flex;
+        align-items: center;
+        gap: 10px;
+        .chat-item-tab{
+            background-color: #f7f9fc;
+            border: 1px solid transparent;
+            color: #1d2129;
+            padding: 10px;
+            cursor: pointer;
+            border-radius: 5px;
+            &:hover{
+                background: #f0fbff;
+                border-color: transparent;
+                color: #08f;
+            }
+            &.active{
+                background: #f0fbff;
+                border-color: transparent;
+                color: #08f;
+            }
+        }
+    }
+}
+.user-info {
+    display: flex;
+    align-items: center;
+    border-bottom: 1px solid var(--el-border-color-light);
+    gap: 15px;
+    padding: 10px 20px;
+    .avatar{
+        border:1px solid var(--el-border-color-light);
+        border-radius: 5px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        img {
+            width: 50px;
+            height: 50px;
+        }
+    }
+    .info {
+        .name {
+            font-size: 16px;
+            font-weight: 800;
+            margin-bottom: 10px;
+        }
+    }
+    .user-state{
+        font-size: 12px;
+        display: flex;
+        align-items: center;
+        cursor: pointer;
+        .names {
+            font-size: 14px;
+            display: flex;
+            align-items: center;
+            gap: 5px;
+            text {
+                width: 10px;
+                height: 10px;
+                border-radius: 10px;
+                &.success{
+                    background-color: #6ccc3d;
+                }
+                &.info{
+                    background-color: #64676c;
+                }
+            }
+        }
+    }
+}
+.state-item{
+    font-size: 12px;
+    .name {
+        font-size: 14px;
+        display: flex;
+        align-items: center;
+        gap: 5px;
+        text {
+            width: 10px;
+            height: 10px;
+            border-radius: 10px;
+            &.success{
+                background-color: #6ccc3d;
+            }
+            &.info{
+                background-color: #64676c;
+            }
+        }
+    }
+}
+</style>

+ 3 - 0
src/views/service/chat/components/asideRight.vue

@@ -0,0 +1,3 @@
+<template>
+
+</template>

+ 167 - 0
src/views/service/chat/components/chatBody.vue

@@ -0,0 +1,167 @@
+<template>
+    <div class="chat-body-components" v-if="!isChat">
+        <div class="empty-data">
+            <img src="https://lf-govern-cdn-tos.bytedcdn.com/obj/life-governance-cdn/life-im-pc/static/image/empty.efbaf24f.png" />
+            请从左侧列表选择一个用户开始聊天
+        </div>
+    </div>
+    <div class="chat-body-components" v-else>
+        <div class="custom-info">
+            <div class="name">与xxx对话中</div>
+        </div>
+        <div class="chat-content">
+            <div class="chat-content-body">
+                <div class="chat-loading-sk" v-for="(item,indx) in 20" v-if="userLoading">
+                    <el-skeleton :animated="true">
+                        <template #template>
+                            <div class="chat-sk-flex">
+                                <el-skeleton-item variant="image" style="width: 40px; height: 40px" />
+                                <div class="sk-right">
+                                    <el-skeleton-item variant="h3" style="width: 50%" />
+                                    <div style="margin-top: 5px;">
+                                        <el-skeleton-item variant="text" style="width: 30%;" />
+                                    </div>
+                                </div>
+                                <div class="time">
+                                    <el-skeleton-item variant="text" />
+                                </div>
+                            </div>
+                        </template>
+                    </el-skeleton>
+                </div>
+            </div>
+        </div>
+        <div class="chat-send">
+            <div class="quick-group">
+                <div class="emoji-item">
+                    <el-popover placement="top" :width="400" trigger="click">
+                        <template #reference>
+                            <div class="item-btn">
+                                <el-image style="width:25px;height:25px;" src="https://jymini.oss-cn-guangzhou.aliyuncs.com/pc/face.svg"></el-image>
+                                <div class="name">表情</div>
+                            </div>
+                        </template>
+                    </el-popover>
+                </div>
+                <div class="emoji-item">
+                    <el-popover placement="top" :width="174">
+                        <template #reference>
+                            <div class="item-btn">
+                                <el-image style="width:25px;height:25px;" src="https://jymini.oss-cn-guangzhou.aliyuncs.com/pc/more.svg"></el-image>
+                                <div class="name">图片</div>
+                            </div>
+                        </template>
+                        <sc-upload v-model="uploadImg" :on-success="uploadSuccess"></sc-upload>
+                    </el-popover>
+                </div>
+                <div class="emoji-item" @click="showQuick">
+                    <el-popover placement="top" :width="400" trigger="click" @show="getQuick">
+                        <template #reference>
+                            <div class="item-btn">
+                                <el-image style="width:25px;height:25px;" src="https://jymini.oss-cn-guangzhou.aliyuncs.com/pc/quick.svg"></el-image>
+                                <div class="name">快捷回复</div>
+                            </div>
+                        </template>
+                    </el-popover>
+                </div>
+            </div>
+            <div class="send-body">
+                <el-input
+                    type="textarea"
+                    :rows="5"
+                    maxlength="200"
+                    v-model="inputMessage"
+                    placeholder="请输入消息..."
+                    @keyup.enter.native="handleKeyCode"
+                    @keydown.native="handleKeyCode"
+                    show-word-limit
+                ></el-input>
+                <div class="send-btn-group">
+                    <el-button type="primary" @click="sendMessage">发送</el-button>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    data () {
+        return {
+            userLoading:true,
+            inputMessage:"",
+            isChat:false
+        }
+    },
+    props: {
+        userInfo: { type: Object, default: () => {} }
+    },
+    methods: {
+
+    }
+}
+</script>
+
+<style scoped>
+.empty-data{
+    display: flex;width: 100%;text-align: center;justify-content: center;font-size: 14px;background-color: #f8f8f8;align-items: center;height: 100%;
+    color: #95989d;
+    flex-direction: column;
+    img {
+        width: 170px;
+    }
+}
+.chat-body-components{
+    background-color: #f8f8f8;
+    display: flex;
+    flex-direction: column;
+    position: fixed;
+    z-index: 1;
+    top: 0;
+    left: 300px;
+    bottom: 0;
+    right: 400px;
+    .chat-content{
+        flex: 1;
+        overflow: auto;
+        .chat-content-body {
+            width: 98%;
+            margin: 0 auto;
+        }
+    }
+    .custom-info{
+        background-color: #fff;
+        height: 60px;
+        line-height: 60px;
+        padding: 0 10px;
+        border-bottom: 1px solid var(--el-border-color-light);
+        .name {
+            font-size: 16px;
+            font-weight: bold;
+        }
+    }
+    .chat-send{
+        width: 98%;
+        margin: 0 auto;
+        border: 1px solid var(--el-border-color-light);
+        border-radius: 10px;
+        background-color: #fff;
+        padding: 10px 20px;
+        .quick-group{
+            display: flex;align-items: center;gap: 10px;
+            .item-btn{
+                padding: 5px;border-radius: 3px;display: flex;align-items: center;gap: 5px;cursor: pointer;
+            }
+        }
+        .send-body{
+            margin-top: 10px;
+        }
+        .send-btn-group{
+            margin-top: 10px;
+            display: flex;
+            align-items: center;
+            justify-content: flex-end;
+        }
+    }
+}
+</style>

+ 60 - 0
src/views/service/chat/web/index.vue

@@ -0,0 +1,60 @@
+<template>
+    <div class="router-err" v-if="userInfo.type !== 3">
+        <div class="router-err__icon">
+            <img src="img/404.png" />
+        </div>
+        <div class="router-err__content">
+            <h2>无权限或找不到页面</h2>
+            <p>当前页面无权限访问或者打开了一个不存在的链接,请检查当前账户权限和链接的可访问性。</p>
+        </div>
+    </div>
+    <el-container class="flex-column" v-else>
+        <el-main class="nopadding">
+            <el-container>
+                <el-aside width="300px">
+                    <asideMain ref="asideMain" :userInfo="userInfo"></asideMain>
+                </el-aside>
+                <el-container>
+                    <chatMain ref="chatMain" :userInfo="userInfo"></chatMain>
+                </el-container>
+                <el-aside width="400px">
+                    <rightMain ref="rightMain" :userInfo="userInfo"></rightMain>
+                </el-aside>
+            </el-container>
+        </el-main>
+    </el-container>
+</template>
+
+<script>
+import asideMain from '../components/aside';
+import rightMain from '../components/asideRight';
+import chatMain from '../components/chatBody';
+export default {
+    components: {
+        asideMain,chatMain,rightMain
+    },
+    data(){
+        return {
+            userInfo:null,
+        }
+    },
+
+	created() {
+		var userInfo = this.$TOOL.data.get("USER_INFO");
+        this.userInfo = userInfo;
+    }
+}
+</script>
+
+<style scoped lang="scss">
+.router-err {display: flex;width: 900px;margin: 50px auto;align-items: center;}
+.router-err__icon {width: 400px;}
+.router-err__icon img {width: 100%;}
+.router-err__content {flex: 1;padding:40px;}
+.router-err__content h2 {font-size: 26px;}
+.router-err__content p {font-size: 14px;color: #999;margin: 15px 0 30px 0;line-height: 1.5;}
+@media (max-width: 992px){
+    .router-err {display: block;width: 100%;margin-top: 10px;text-align: center;}
+    .router-err__icon {width: 280px;margin: 0 auto;}
+}
+</style>