1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069 |
- <link rel="stylesheet" href="//at.alicdn.com/t/c/font_2385137_b8qygb2jne.css?v={$site.version|htmlentities}">
- <link rel="stylesheet" href="__CDN__/assets/addons/shopro/css/index.css?v={$site.version|htmlentities}">
- __DARK__
- <style>
- #sa-chat {
- position: absolute;
- right: 20px;
- bottom: 20px;
- z-index: 1000;
- }
- #sa-chat .chat-button {
- width: 40px;
- height: 40px;
- background: var(--sa-background-assist);
- box-shadow: 0px 1px 16px #e4e4e4;
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- }
- #sa-chat .chat-button:hover {
- background: var(--sa-table-header-bg);
- }
- #sa-chat .chat-icon {
- font-size: 20px;
- color: var(--el-color-primary);
- }
- .sa-shopro-drawer {
- top: 50px !important;
- width: 380px !important;
- height: calc(100% - 50px) !important;
- }
- .sa-shopro-drawer .el-drawer__body {
- padding: 0;
- }
- .sa-shopro-drawer .chat-container {
- height: 100%;
- flex-direction: column;
- }
- .sa-shopro-drawer .chat-header {
- height: 50px;
- background: var(--t-btn-hover);
- padding: 0 12px;
- color: var(--sa-background-assist);
- position: relative;
- }
- .sa-shopro-drawer .chat-header .circle-close-filled {
- font-size: 16px;
- cursor: pointer;
- }
- .sa-shopro-drawer .chat-header .circle-close-filled:hover {
- color: var(--el-color-primary);
- }
- .sa-shopro-drawer .drawer-tabs {
- width: fit-content;
- flex: unset;
- height: 36px;
- padding: 0 2px;
- border-radius: 8px;
- background: var(--t-bg-focus);
- display: flex;
- align-items: center;
- justify-content: center;
- position: relative;
- }
- .sa-shopro-drawer .drawer-tabs .bg {
- position: absolute;
- top: 2px;
- left: 2px;
- width: 118px;
- height: 32px;
- background: var(--sa-background-assist);
- border-radius: 6px;
- transition: all 0.2s;
- }
- .sa-shopro-drawer .drawer-tabs-item {
- width: 118px;
- height: 32px;
- display: flex;
- align-items: center;
- justify-content: center;
- position: relative;
- z-index: 1;
- padding: 0 7px;
- font-size: 14px;
- color: var(--el-color-primary);
- cursor: pointer;
- }
- .sa-shopro-drawer .chat-main {
- --el-main-padding: 0;
- }
- .sa-shopro-drawer .notification-item-more {
- width: 100%;
- height: 40px;
- line-height: 40px;
- text-align: center;
- font-size: 12px;
- color: var(--sa-subfont);
- }
- .sa-shopro-drawer .empty-icon {
- width: 150px;
- height: 150px;
- }
- .sa-shopro-drawer .empty-description {
- width: 200px;
- font-size: 16px;
- color: var(--sa-subfont);
- }
- .sa-chat-drawer .avatar {
- position: relative;
- width: 36px;
- height: 36px;
- }
- .sa-chat-drawer .avatar .avatar-bage {
- position: absolute;
- right: 0;
- bottom: 2px;
- height: 10px;
- width: 10px;
- padding: 0;
- background: #fff;
- border-radius: 50%;
- }
- .sa-chat-drawer .avatar .avatar-bage img {
- width: 100%;
- }
- .status-popover {
- width: 104px !important;
- min-width: 104px !important;
- }
- .status-popover img {
- width: 12px;
- height: 12px;
- }
- .customer-service {
- width: 122px;
- color: var(--sa-background-assist);
- }
- .customer-service .customer-service-name {
- height: 16px;
- line-height: 16px;
- font-size: 14px;
- font-weight: 400;
- margin-bottom: 4px;
- }
- .customer-service .customer-service-room-name {
- height: 14px;
- line-height: 14px;
- font-weight: 400;
- font-size: 12px;
- }
- .customer-service .customer-service-icon {
- font-size: 12px;
- margin-left: 5px;
- @media only screen and (max-width: 768px) {
- font-size: 16px;
- }
- }
- .sa-chat-drawer .chat-header .drawer-tabs .bg {
- width: 50px;
- }
- .sa-chat-drawer .chat-header .drawer-tabs .drawer-tabs-item {
- width: 50px;
- font-size: 12px;
- }
- .sa-chat-drawer .chat-main {
- display: flex;
- overflow: hidden;
- }
- .sa-chat-drawer .chat-main .content-left {
- flex-shrink: 0;
- height: 100%;
- border-right: 1px solid var(--sa-space);
- }
- .sa-chat-drawer .chat-session-item {
- width: 60px;
- transition: all 0.3s linear;
- padding: 10px 0;
- }
- .sa-chat-drawer .chat-session-item:hover {
- background-color: var(--t-bg-active);
- transition: all 0.3s linear;
- }
- .sa-chat-drawer .chat-session-item:hover .chat-session-icon {
- transform: scale(1);
- margin-left: 0;
- transition: all 0.2s linear;
- }
- .sa-chat-drawer .chat-session-item:hover .chat-session-icon:active {
- transform: translate(1px, 1px);
- }
- .sa-chat-drawer .chat-session-item:focus {
- background-color: var(--t-bg-active);
- }
- .sa-chat-drawer .chat-session-item.is-active {
- background-color: var(--t-bg-active);
- transition: all 0.3s linear;
- }
- .sa-chat-drawer .chat-session-item .chat-session-icon {
- height: 12px;
- font-size: 12px;
- color: var(--el-color-primary);
- margin-right: 4px;
- margin-left: -16px;
- transform: scale(0) translate(0, 0);
- transition: all 0.2s linear;
- }
- .sa-chat-drawer .chat-session-item .chat-session-icon .chat-session-circle-close-filled {
- display: none;
- }
- .sa-chat-drawer .chat-session-item .chat-session-icon:hover .chat-session-close {
- display: none;
- }
- .sa-chat-drawer .chat-session-item .chat-session-icon:hover .chat-session-circle-close-filled {
- display: block;
- }
- .sa-chat-drawer .chat-main .content-right {
- width: 100%;
- height: 100%;
- display: flex;
- flex-direction: column;
- }
- .sa-chat-drawer .current-customer {
- width: 100%;
- height: 40px;
- background-color: var(--sa-card-background);
- border-bottom: 1px solid var(--sa-space);
- padding: 0 10px;
- }
- .sa-chat-drawer .current-customer .el-input__inner {
- border: none;
- height: 38px;
- width: 140px;
- color: #8c8c8c;
- }
- .sa-chat-drawer .current-customer .current-customer-name {
- font-size: 14px;
- color: var(--sa-font);
- }
- .sa-chat-drawer .current-customer .current-customer-transfer {
- flex-shrink: 0;
- width: 120px;
- }
- .sa-chat-drawer .current-customer .customer-from {
- font-size: 14px;
- color: #999999;
- }
- .sa-chat-drawer .current-customer .access-btn {
- color: var(--el-color-primary);
- font-size: 12px;
- padding: 10px 20px;
- }
- .sa-chat-drawer .chat-message {
- padding: 0 16px;
- }
- .sa-chat-drawer .message-item {
- margin-bottom: 20px;
- }
- .sa-chat-drawer .message-date {
- color: var(--sa-subfont);
- font-size: 12px;
- }
- .sa-chat-drawer .message-item .message-item-wrap {
- max-width: 80%;
- padding: 12px;
- font-size: 14px;
- color: var(--sa-font);
- white-space: normal;
- word-break: break-all;
- word-wrap: break-word;
- }
- .sa-chat-drawer .message-item.sa-row-right .message-item-wrap {
- background: var(--t-bg-active);
- border-radius: 8px 2px 8px 8px;
- color: var(--sa-font);
- }
- .sa-chat-drawer .message-item.sa-row-left .message-item-wrap {
- background: var(--sa-table-header-bg);
- border-radius: 2px 8px 8px 8px;
- color: var(--sa-font);
- }
- .sa-chat-drawer .message-item .message-emoji {
- width: 24px !important;
- height: 24px;
- margin-right: 4px;
- }
- .sa-chat-drawer .message-item .message-emoji:last-of-type {
- margin-right: 0;
- }
- .sa-chat-drawer .message-item img {
- width: 100% !important;
- }
- .sa-chat-drawer .message-item .goods-item .el-image {
- flex-shrink: 0;
- width: 40px;
- height: 40px;
- }
- .sa-chat-drawer .message-item .order-sn {
- font-size: 12px;
- color: var(--el-color-primary);
- }
- .sa-chat-drawer .message-item .order-goods {
- padding: 8px;
- background: var(--sa-background-assist);
- border-radius: 4px;
- }
- .sa-chat-drawer .message-item .order-goods .el-image {
- flex-shrink: 0;
- width: 40px;
- height: 40px;
- }
- .sa-chat-drawer .message-item .order-goods .order-goods-price,
- .sa-chat-drawer .message-item .order-goods .order-goods-total {
- font-size: 12px;
- color: var(--sa-subfont);
- }
- .sa-chat-drawer .chat-footer {
- --el-footer-padding: 0;
- --el-footer-height: 140px;
- border-top: 1px solid var(--sa-space);
- }
- .sa-chat-drawer .chat-footer .chat-footer-input {
- width: 100%;
- height: 84px;
- overflow-y: auto;
- padding: 10px;
- font-size: 14px;
- line-height: 20px;
- color: var(--sa-font);
- border: none;
- outline: none;
- margin-bottom: 10px;
- }
- .sa-chat-drawer .chat-footer .chat-footer-bottom {
- padding: 0 12px;
- }
- .sa-chat-drawer .chat-footer .chat-footer-bottom .iconfont {
- font-size: 18px;
- }
- .emoji-popover {
- padding: 12px 0 0 12px !important;
- }
- .emoji-popover .emoji-icon {
- width: 20px;
- height: 20px;
- margin-right: 6px;
- margin-bottom: 6px;
- }
- .emoji-popover .emoji-icon img {
- width: 100%;
- }
- .common-words-popover {
- padding: 0 !important;
- }
- .common-words-popover .common-words-title {
- font-size: 14px;
- color: #8c8c8c;
- height: 40px;
- line-height: 40px;
- padding-left: 17px;
- border-bottom: 1px solid var(--sa-border);
- }
- .common-words-popover .common-words-item {
- color: var(--sa-font);
- font-size: 14px;
- height: 40px;
- line-height: 40px;
- border-bottom: 1px solid var(--sa-border);
- padding-left: 20px;
- }
- .common-words-popover .common-words-item:hover {
- background: rgba(128, 106, 246, 0.08);
- }
- .sa-chat-drawer .connect-status {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- font-size: 14px;
- color: var(--sa-subtitle);
- }
- .sa-chat-drawer .connect-status .chat-reconnect-failed {
- width: 150px;
- height: 150px;
- margin-bottom: 30px;
- }
- .sa-chat-drawer .connect-status .connect-status-dot {
- font-family: simsun;
- display: inline-block;
- width: 1.5em;
- vertical-align: bottom;
- overflow: hidden;
- animation: dot 3s infinite step-start;
- }
- @-webkit-keyframes dot {
- 0% {
- width: 0;
- margin-right: 1.5em;
- }
- 33% {
- width: 0.5em;
- margin-right: 1em;
- }
- 66% {
- width: 1em;
- margin-right: 0.5em;
- }
- 100% {
- width: 1.5em;
- margin-right: 0;
- }
- }
- .sa-chat-drawer .connect-status .reconnect-button {
- color: var(--el-color-primary);
- cursor: pointer;
- }
- .sa-notification-drawer .chat-header .circle-close-filled {
- position: absolute;
- top: 50%;
- right: 12px;
- margin-top: -8px;
- font-size: 16px;
- }
- .sa-notification-drawer .notification-item {
- width: 100%;
- padding: 16px;
- border-bottom: 1px solid var(--sa-space);
- }
- .sa-notification-drawer .notification-item .notification-item-time {
- font-family: PingFang SC;
- font-size: 12px;
- color: var(--sa-subfont);
- }
- .sa-notification-drawer .notification-item .notification-item-top {
- display: flex;
- width: inherit;
- overflow: hidden;
- }
- .sa-notification-drawer .notification-item .text {
- font-size: 14px;
- color: var(--sa-font);
- overflow: hidden;
- text-overflow: ellipsis;
- text-align: justify;
- position: relative;
- line-height: 1.5;
- max-height: 3em;
- transition: 0.3s max-height;
- white-space: normal;
- word-break: break-all;
- }
- .sa-notification-drawer .notification-item .text::before {
- content: '';
- height: calc(100% - 21px);
- float: right;
- }
- .sa-notification-drawer .notification-item .text::after {
- content: '';
- width: 999vw;
- height: 999vw;
- position: absolute;
- box-shadow: inset calc(100px - 999vw) calc(21px - 999vw) 0 0 var(--el-bg-color);
- margin-left: -100px;
- }
- .sa-notification-drawer .notification-item .notification-item-button {
- position: relative;
- float: right;
- clear: both;
- margin-left: 20px;
- line-height: 1.5;
- padding: 0 8px;
- font-size: 12px;
- color: var(--el-color-primary);
- cursor: pointer;
- }
- .sa-notification-drawer .notification-item .notification-item-button::after {
- content: '展开';
- }
- .sa-notification-drawer .notification-item .exp {
- display: none;
- }
- .sa-notification-drawer .notification-item .exp:checked+.text {
- max-height: none;
- }
- .sa-notification-drawer .notification-item .exp:checked+.text::after {
- visibility: hidden;
- }
- .sa-notification-drawer .notification-item .exp:checked+.text .notification-item-button::before {
- visibility: hidden;
- }
- .sa-notification-drawer .notification-item .exp:checked+.text .notification-item-button::after {
- content: '收起';
- }
- .sa-notification-drawer .notification-item .notification-item-button::before {
- content: '...';
- position: absolute;
- left: -5px;
- color: var(--sa-font);
- transform: translateX(-100%);
- }
- .sa-notification-drawer .notification-item.is-read .text,
- .sa-notification-drawer .notification-item.is-read .notification-item-time,
- .sa-notification-drawer .notification-item.is-read .notification-item-button::before {
- color: var(--sa-place);
- }
- .sa-notification-drawer .chat-footer {
- --el-footer-height: 40px;
- border-top: 1px solid var(--sa-space);
- }
- </style>
- <script type="text/x-template" id="saChatTemplate">
- <div id="sa-chat">
- <div class="chat-button mb-2" @click="onShowNotification">
- <el-badge is-dot :hidden="!isNotificationUnreadNum">
- <i class="iconfont iconNotification1 chat-icon"></i>
- </el-badge>
- </div>
- <div class="chat-button" @click="onShowChat">
- <el-badge is-dot :hidden="chat.state.connection.status != 'connect' || !isChatUnreadNum">
- <i v-if="chat.state.connection.status === 'reconnect_failed'" class="iconfont iconChat1 chat-icon"></i>
- <i v-else class="iconfont iconChat chat-icon"></i>
- </el-badge>
- </div>
- <el-drawer v-model="showChat" direction="rtl" custom-class="sa-chat-drawer sa-shopro-drawer"
- modal-class="sa-chat-drawer-overlay" :show-close="false" :with-header="false">
- <el-container class="chat-container">
- <!-- 连接成功 -->
- <template v-if="chat.state.connection.status == 'connect'">
- <el-header class="chat-header sa-flex sa-row-between">
- <!-- 客服 -->
- <div class="sa-flex">
- <el-popover v-if="chat.state.currentCustomerService.name" placement="bottom-start" trigger="click"
- popper-class="status-popover" :show-arrow="false">
- <div class="sa-flex sa-row-center cursor-pointer"
- v-for="(value,key) in customerServiceStatus"
- @click="onChangeCustomerServiceStatus(key)">
- <img :src="`/assets/addons/shopro/img/chat/status-${key}.png`" />
- <span class="ml-2">{{value}}</span>
- </div>
- <template #reference>
- <div class="avatar mr-2 cursor-pointer">
- <el-avatar :size="36" :src="Fast.api.cdnurl(chat.state.currentCustomerService.avatar)">
- <img src="/assets/addons/shopro/img/default-avatar.png" />
- </el-avatar>
- <div class="avatar-bage sa-flex sa-row-center">
- <img
- :src="`/assets/addons/shopro/img/chat/status-${chat.state.currentCustomerService.status}.png`" />
- </div>
- </div>
- </template>
- </el-popover>
- <div v-if="chat.state.customerServiceIdentityList.length==0" class="customer-service sa-flex">
- <div class="sa-flex-col">
- <div class="customer-service-name sa-table-line-1">
- {{ chat.state.currentCustomerService.name }}
- </div>
- <div class="customer-service-room-name sa-table-line-1">{{
- chat.state.currentCustomerService.room_name }}</div>
- </div>
- </div>
- <el-dropdown v-if="chat.state.customerServiceIdentityList.length > 0" trigger="click">
- <div class="customer-service sa-flex">
- <div class="sa-flex-col cursor-pointer">
- <div class="customer-service-name sa-table-line-1">
- {{ chat.state.currentCustomerService.name }}
- </div>
- <div class="customer-service-room-name sa-table-line-1">{{
- chat.state.currentCustomerService.room_name }}
- </div>
- </div>
- <el-icon class="customer-service-icon">
- <arrow-down />
- </el-icon>
- </div>
- <template #dropdown>
- <el-dropdown-menu>
- <el-dropdown-item v-for="item in chat.state.customerServiceIdentityList"
- :key="item.value" @click="onChangeCustomerServiceIdentity(item.value)">{{
- item.label }}
- </el-dropdown-item>
- </el-dropdown-menu>
- </template>
- </el-dropdown>
- </div>
- <!-- 聊天类型 -->
- <div class="sa-flex">
- <div class="drawer-tabs sa-flex sa-col-center">
- <div class="bg" :style="{ left: sessionTypeList[chat.state.sessionType]?.left }">
- </div>
- <el-badge v-for="(value,key) in sessionTypeList" :is-dot="key=='waiting'"
- :hidden="!chat.state.customerWaitingList.length">
- <div class="drawer-tabs-item" @click="onChangeSessionType(key)">
- {{value.label}}
- </div>
- </el-badge>
- </div>
- <el-icon class="circle-close-filled ml-2" @click="showChat=false">
- <circle-close-filled />
- </el-icon>
- </div>
- </el-header>
- <el-main class="chat-main">
- <div class="chat-content sa-flex sa-flex-1">
- <!-- 会话列表 -->
- <div class="content-left">
- <el-scrollbar class="chat-session" :min-size="10">
- <div class="sa-flex-col sa-row-center sa-col-center">
- <div class="chat-session-item sa-flex sa-col-center sa-row-center" :class="{
- 'is-active': currentSessionTypeIndexs[chat.state.sessionType] == index,
- }" v-for="(item, index) in chat.state.sessionList"
- @click="onChangeCurrentSessionTypeIndex(index)">
- <template v-if="chat.state.sessionType == 'ing'">
- <el-popconfirm width="fit-content" title="确定结束当前会话吗?"
- @confirm="onDeleteSession(item.session_id, index, chat.state.sessionType)">
- <template #reference>
- <div class="chat-session-icon cursor-pointer">
- <el-icon class="chat-session-close">
- <close />
- </el-icon>
- <el-icon class="chat-session-circle-close-filled">
- <circle-close-filled />
- </el-icon>
- </div>
- </template>
- </el-popconfirm>
- </template>
- <template v-if="chat.state.sessionType == 'history'">
- <el-popover popper-class="sa-popper"
- v-model:visible="historyDeletePopover.flag[index]" placement="bottom"
- trigger="click">
- <div class="sa-flex">
- <el-icon class="sa-color--warning mr-1">
- <question-filled />
- </el-icon>确定删除此顾客吗?
- </div>
- <el-checkbox v-model="historyDeletePopover.is_del_record"
- :true-label="1" :false-label="0" label="删除聊天记录"></el-checkbox>
- <div class="sa-flex sa-row-right">
- <el-button size="small" link
- @click="onCancelHistoryDeletePopover(index)">取消</el-button>
- <el-button type="primary" size="small"
- @click="onConfirmHistoryDeletePopover(item.session_id, index, chat.state.sessionType)">
- 确定</el-button>
- </div>
- <template #reference>
- <div class="chat-session-icon cursor-pointer">
- <el-icon class="chat-session-close">
- <close />
- </el-icon>
- <el-icon class="chat-session-circle-close-filled">
- <circle-close-filled />
- </el-icon>
- </div>
- </template>
- </el-popover>
- </template>
- <el-tooltip :content="item.nickname" placement="right" effect="dark">
- <el-badge class="avatar cursor-pointer" type="danger"
- :value="item.unread_num" :max="99" :hidden="!item.unread_num">
- <el-avatar :size="36" :src="Fast.api.cdnurl(item.avatar)">
- <img src="/assets/addons/shopro/img/default-avatar.png" />
- </el-avatar>
- <div class="avatar-bage sa-flex sa-row-center">
- <img
- :src="`/assets/addons/shopro/img/chat/status-${item.status?'online':'disconnect'}.png`" />
- </div>
- </el-badge>
- </el-tooltip>
- </div>
- </div>
- </el-scrollbar>
- </div>
- <div class="content-right">
- <!-- 当前顾客 -->
- <div v-if="chat.state.currentCustomer"
- class="current-customer sa-flex sa-col-center sa-p-l-17">
- <div v-if="chat.state.currentCustomer?.session_id"
- class="sa-flex sa-flex-1 sa-row-between">
- <div class="current-customer-name sa-flex sa-flex-1" @click="toDetail">
- {{ chat.state.currentCustomer?.nickname || '' }}
- </div>
- <div v-if="chat.state.sessionType == 'ing' && avaliableCustomerServicesList.length"
- class="current-customer-transfer sa-flex">
- <el-dropdown trigger="click" @command="onTransferCommand">
- <div class="el-dropdown-link sa-flex">
- <div class="sa-line-1">
- {{
- avaliableCustomerServicesList.find((item) => item.value ==
- transferCustomer)
- ?.label || '选择转接的客服'
- }}
- </div>
- <el-icon class="el-icon--right">
- <arrow-down />
- </el-icon>
- </div>
- <template #dropdown>
- <el-dropdown-menu>
- <el-dropdown-item v-for="item in avaliableCustomerServicesList"
- :key="item.value" :command="item.value"
- :disabled="item.disabled">
- {{ item.label }}
- </el-dropdown-item>
- </el-dropdown-menu>
- </template>
- </el-dropdown>
- <el-button v-if="transferCustomer" class="ml-1" type="primary" link size="small"
- @click="onTransferCustomer">
- 转接
- </el-button>
- </div>
- <el-button v-if="chat.state.sessionType == 'waiting'" type="primary" link
- @click="onAccessCustomer">
- 立即接入
- </el-button>
- </div>
- </div>
- <el-alert v-if="!chat.state.currentCustomer" type="warning" center>
- <template #title>暂无顾客会话</template>
- </el-alert>
- <el-scrollbar class="chat-message" ref="chatScrollRef">
- <template v-if="chat.state.sessionList.length && chat.state.chatList.length">
- <!-- 加载状态 -->
- <div class="notification-item-more">
- <el-button
- v-if="chat.state.historyPagination.page < chat.state.historyPagination.lastPage"
- type="info" link size="small" @click="onLoadMore">
- {{loadingMap[chat.state.historyPagination.loadStatus].title}}
- </el-button>
- <div v-else>
- {{ loadingMap[chat.state.historyPagination.loadStatus].title}}
- <i class="ml-1"
- :class="loadingMap[chat.state.historyPagination.loadStatus].icon"></i>
- </div>
- </div>
- <template v-for="(item,index) in chat.state.chatList">
- <div class="sa-flex sa-row-center">
- <div v-if="item.sender_identify == 'system'" class="message-system mb-4">
- {{ item.content.text }}
- </div>
- <div v-if="item.sender_identify != 'system' && showTime(item, index)"
- class="message-date mb-4">
- {{ formatTime(item.createtime) }}
- </div>
- </div>
- <div class="message-item sa-flex" :class="[
- item.sender_identify == 'customer_service'
- ? 'sa-row-right'
- : item.sender_identify == 'customer'
- ? 'sa-row-left'
- : '',
- ]">
- <div class="message-item-wrap">
- <!-- 文本 -->
- <template v-if="item.message_type=='text'">
- <div v-html="replaceEmoji(item.message)"></div>
- </template>
- <!-- 图片 -->
- <template v-if="item.message_type=='image'">
- <img :src="Fast.api.cdnurl(item.message)" />
- </template>
- <!-- 商品 -->
- <template v-if="item.message_type=='goods'">
- <div class="goods-item sa-flex cursor-pointer"
- @click="onOpenGoodsDetail(item.message.id)">
- <el-image class="mr-2"
- :src="Fast.api.cdnurl(item.message.image)">
- </el-image>
- <div>
- <div class="sa-table-line-1">{{item.message.title}}
- </div>
- <div class="sa-color--danger">
- ¥{{item.message.price.join(',')}}</div>
- </div>
- </div>
- </template>
- <!-- 订单 -->
- <template v-if="item.message_type=='order'">
- <div class="order-item cursor-pointer"
- @click="onOpenOrderDetail(item.message.id)">
- <div class="order-sn mb-2">{{item.message.order_sn}}</div>
- <div class="order-goods sa-flex">
- <el-image class="mr-2"
- :src="Fast.api.cdnurl(item.message.items[0]?.goods_image)">
- </el-image>
- <div>
- <div class="sa-table-line-1">
- {{item.message.items[0]?.goods_title}}
- </div>
- <div class="sa-flex sa-row-between">
- <div class="order-goods-price">
- 共{{item.message.items.length}}件商品
- </div>
- <div class="order-goods-total">合计
- ¥{{item.message.pay_fee}}</div>
- </div>
- </div>
- </div>
- </div>
- </template>
- </div>
- </div>
- </template>
- </template>
- <!-- 置空页 -->
- <el-empty v-if="!chat.state.chatList.length">
- <template #image>
- <img class="empty-icon" src="/assets/addons/shopro/img/chat/chat-empty.png" />
- </template>
- <template #description>
- <div class="empty-description">暂时没有会话哦!</div>
- </template>
- </el-empty>
- </el-scrollbar>
- </div>
- </div>
- </el-main>
- <el-footer v-if="chat.state.currentCustomer" class="chat-footer">
- <div class="chat-footer-input" ref="messageInputRef" contenteditable="true" @input="getMessageInput"
- placeholder="请输入内容,按Enter直接发送消息" @keydown="onKeyDown" @dragover.prevent></div>
- <div class="chat-footer-bottom sa-flex sa-row-between">
- <!-- 会话工具栏 -->
- <div class="sa-flex">
- <!-- 表情 -->
- <el-popover placement="top-start" :width="260" trigger="click" popper-class="emoji-popover">
- <div class="sa-flex sa-flex-wrap">
- <div class="sa-flex sa-row-center sa-col-center emoji-icon"
- @click="onSelectToolbar('emoji',item)" @mousedown.prevent
- v-for="(item, index) in emojiList" :key="index">
- <img :src="`/assets/addons/shopro/img/chat/emoji/${item.file}`" />
- </div>
- </div>
- <template #reference>
- <el-button link>
- <i class="iconfont iconbiaoqing"></i>
- </el-button>
- </template>
- </el-popover>
- <!-- 常用语 -->
- <el-popover placement="top-start" :width="200" trigger="click"
- popper-class="common-words-popover">
- <div class="common-words-title">常用语</div>
- <div class="common-words-item sa-line-1" v-for="item in chat.state.commonWords"
- :key="item.id" @click="onSelectToolbar('text',item.content)">
- {{ item.name }}
- </div>
- <template #reference>
- <el-button link>
- <i class="iconfont iconchangyongyu-011"></i>
- </el-button>
- </template>
- </el-popover>
- <!-- 商品 -->
- <el-button link @click="onSelectToolbar('goods')">
- <i class="iconfont iconshangpin"></i>
- </el-button>
- <!-- 文件 -->
- <el-button link @click="onSelectToolbar('image')">
- <i class="iconfont iconwenjian-01"></i>
- </el-button>
- </div>
- <el-button class="send-btn" type="primary"
- :disabled="!messageInput || !chat.state.currentCustomer" @click="onSendMessage">发送
- </el-button>
- </div>
- </el-footer>
- </template>
- <!-- 未连接 -->
- <el-main v-if="chat.state.connection.status != 'connect'" class="connect-status">
- <img class="chat-reconnect-failed" src="/assets/addons/shopro/img/chat/chat-reconnect-failed.png" />
- <div v-if="chat.state.connection.status === 'error'">请检查您的网络连接</div>
- <div v-if="chat.state.connection.status === 'connecting'">
- 正在连接Websocket服务
- <span class="connect-status-dot">...</span>
- </div>
- <div v-if="chat.state.connection.status === 'reconnecting'">
- ({{ chat.state.connection.attempts }}/{{
- chat.state.connection.reconnectionAttempts
- }})正在重新连接Websocket服务
- <span class="connect-status-dot">...</span>
- </div>
- <template v-if="chat.state.connection.status === 'reconnect_error'">
- <div>
- ({{ chat.state.connection.attempts }}/{{ chat.state.connection.reconnectionAttempts }})
- WebSocket服务连接失败
- </div>
- <div class="mt-1">
- {{ chat.state.connection.delay }} 秒后尝试重新连接
- <span class="connect-status-dot">...</span>
- </div>
- </template>
- <template v-if="chat.state.connection.status === 'reconnect_failed'">
- <div>Websocket服务连接失败,请检查您的环境后点击 </div>
- <div class="reconnect-button mt-1" @click="onReconnect">重新连接</div>
- </template>
- </el-main>
- </el-container>
- </el-drawer>
- <el-drawer v-model="showNotification" direction="rtl" custom-class="sa-notification-drawer sa-shopro-drawer"
- :show-close="false" :with-header="false">
- <el-container class="chat-container">
- <el-header class="chat-header sa-flex sa-row-center">
- <div class="sa-flex">
- <div class="drawer-tabs sa-flex sa-col-center">
- <div class="bg" :style="{left:chat.state.notificationType=='shop'?'120px':''}">
- </div>
- <div class="drawer-tabs-item" v-for="item in chat.state.notificationTypeList"
- @click="onChangeNotificationType(item.value)">
- <el-badge is-dot :hidden="!item.unread_num">
- {{ item.label }}
- </el-badge>
- </div>
- </div>
- <el-icon class="circle-close-filled ml-2" @click="showNotification=false">
- <circle-close-filled />
- </el-icon>
- </div>
- </el-header>
- <el-main class="chat-main">
- <el-scrollbar height="100%">
- <template v-if="chat.state.notificationList.length">
- <div class="notification-item" :class="item.read_time ? 'is-read' : ''"
- v-for="(item, index) in chat.state.notificationList" @click="onReadNotification(item.id, index)">
- <div class="notification-item-top">
- <input :id="`exp-${index}`" class="exp" type="checkbox" @click.stop />
- <div class="text">
- <label class="notification-item-button" :for="`exp-${index}`" @click.stop></label>
- 【{{ item.data.message_title }}】{{ item.data.message_text }}
- </div>
- </div>
- <span class="notification-item-time">{{ item.createtime }}</span>
- </div>
- <!-- 加载状态 -->
- <div class="notification-item-more">
- <el-button v-if="pagination.page < pagination.lastPage" type="info" link size="small"
- @click="onLoadMoreNotification">
- {{loadingMap[pagination.loadStatus].title}}
- </el-button>
- <div v-else>
- {{ loadingMap[pagination.loadStatus].title}}
- <i class="ml-1" :class="loadingMap[pagination.loadStatus].icon"></i>
- </div>
- </div>
- </template>
- <!-- 置空页 -->
- <el-empty v-if="!chat.state.notificationList.length">
- <template #image>
- <img class="empty-icon" src="/assets/addons/shopro/img/chat/notification-empty.png" />
- </template>
- <template #description>
- <div class="empty-description"> 您的工作效率很高哦, 现在还没有新的待办消息! </div>
- </template>
- </el-empty>
- </el-scrollbar>
- </el-main>
- <el-footer class="chat-footer sa-flex sa-row-center">
- <el-button link size="small" @click="onClearNotification">清空 已读消息</el-button>
- </el-footer>
- </el-container>
- </el-drawer>
- </div>
- </script>
|