mirror of
				https://gitee.com/hhyykk/ipms-sjy-ui.git
				synced 2025-11-04 20:28:45 +08:00 
			
		
		
		
	【新增】:mall 客服初始化
This commit is contained in:
		@@ -29,5 +29,8 @@ VITE_BASE_PATH=/
 | 
			
		||||
# 商城H5会员端域名
 | 
			
		||||
VITE_MALL_H5_DOMAIN='http://localhost:3000'
 | 
			
		||||
 | 
			
		||||
# 客户端静态资源地址 空=默认使用服务端指定的CDN资源地址前缀 | local=本地  |  http(s)://xxx.xxx=自定义静态资源地址前缀
 | 
			
		||||
VITE_STATIC_URL = https://file.sheepjs.com
 | 
			
		||||
 | 
			
		||||
# 验证码的开关
 | 
			
		||||
VITE_APP_CAPTCHA_ENABLE=false
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										71
									
								
								src/api/mall/promotion/kefu/conversation/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/api/mall/promotion/kefu/conversation/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
import request from '@/config/axios'
 | 
			
		||||
 | 
			
		||||
export interface KeFuConversationRespVO {
 | 
			
		||||
  /**
 | 
			
		||||
   * 编号
 | 
			
		||||
   */
 | 
			
		||||
  id: number
 | 
			
		||||
  /**
 | 
			
		||||
   * 会话所属用户
 | 
			
		||||
   */
 | 
			
		||||
  userId: number
 | 
			
		||||
  /**
 | 
			
		||||
   * 会话所属用户头像
 | 
			
		||||
   */
 | 
			
		||||
  userAvatar: string
 | 
			
		||||
  /**
 | 
			
		||||
   * 会话所属用户昵称
 | 
			
		||||
   */
 | 
			
		||||
  nickname: string
 | 
			
		||||
  /**
 | 
			
		||||
   * 最后聊天时间
 | 
			
		||||
   */
 | 
			
		||||
  lastMessageTime: Date
 | 
			
		||||
  /**
 | 
			
		||||
   * 最后聊天内容
 | 
			
		||||
   */
 | 
			
		||||
  lastMessageContent: string
 | 
			
		||||
  /**
 | 
			
		||||
   * 最后发送的消息类型
 | 
			
		||||
   */
 | 
			
		||||
  lastMessageContentType: number
 | 
			
		||||
  /**
 | 
			
		||||
   * 管理端置顶
 | 
			
		||||
   */
 | 
			
		||||
  adminPinned: boolean
 | 
			
		||||
  /**
 | 
			
		||||
   * 用户是否可见
 | 
			
		||||
   */
 | 
			
		||||
  userDeleted: boolean
 | 
			
		||||
  /**
 | 
			
		||||
   * 管理员是否可见
 | 
			
		||||
   */
 | 
			
		||||
  adminDeleted: boolean
 | 
			
		||||
  /**
 | 
			
		||||
   * 管理员未读消息数
 | 
			
		||||
   */
 | 
			
		||||
  adminUnreadMessageCount: number
 | 
			
		||||
  /**
 | 
			
		||||
   * 创建时间
 | 
			
		||||
   */
 | 
			
		||||
  createTime?: string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 客服会话 API
 | 
			
		||||
export const KeFuConversationApi = {
 | 
			
		||||
  // 获得客服会话列表
 | 
			
		||||
  getConversationList: async () => {
 | 
			
		||||
    return await request.get({ url: '/promotion/kefu-conversation/list' })
 | 
			
		||||
  },
 | 
			
		||||
  // 客服会话置顶
 | 
			
		||||
  updateConversationPinned: async (data: any) => {
 | 
			
		||||
    return await request.put({
 | 
			
		||||
      url: '/promotion/kefu-conversation/update-conversation-pinned',
 | 
			
		||||
      data
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
  // 删除客服会话
 | 
			
		||||
  deleteConversation: async (id: number) => {
 | 
			
		||||
    return await request.get({ url: '/promotion/kefu-conversation/delete?id' + id })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -29,8 +29,8 @@
 | 
			
		||||
        :autosize="{ minRows: 2, maxRows: 4 }"
 | 
			
		||||
        :disabled="!getIsOpen"
 | 
			
		||||
        clearable
 | 
			
		||||
        type="textarea"
 | 
			
		||||
        placeholder="请输入你要发送的消息"
 | 
			
		||||
        type="textarea"
 | 
			
		||||
      />
 | 
			
		||||
      <el-select v-model="sendUserId" class="mt-4" placeholder="请选择发送人">
 | 
			
		||||
        <el-option key="" label="所有人" value="" />
 | 
			
		||||
@@ -71,7 +71,7 @@
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { formatDate } from '@/utils/formatTime'
 | 
			
		||||
import { useWebSocket } from '@vueuse/core'
 | 
			
		||||
import { getAccessToken } from '@/utils/auth'
 | 
			
		||||
// import { getAccessToken } from '@/utils/auth'
 | 
			
		||||
import * as UserApi from '@/api/system/user'
 | 
			
		||||
 | 
			
		||||
defineOptions({ name: 'InfraWebSocket' })
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,89 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="kefu">
 | 
			
		||||
    <div
 | 
			
		||||
      v-for="(item, index) in conversationList"
 | 
			
		||||
      :key="item.id"
 | 
			
		||||
      :class="{ active: index === activeConversationIndex }"
 | 
			
		||||
      class="kefu-conversation flex justify-between items-center"
 | 
			
		||||
      @click="openRightMessage(item, index)"
 | 
			
		||||
    >
 | 
			
		||||
      <div class="kefu-conversation-left flex justify-center items-center">
 | 
			
		||||
        <el-avatar :src="item.userAvatar" alt="avatar" />
 | 
			
		||||
        <div class="ml-10px">
 | 
			
		||||
          <div class="nickname">{{ item.nickname }}</div>
 | 
			
		||||
          <div
 | 
			
		||||
            v-dompurify-html="replaceEmoji(item.lastMessageContent)"
 | 
			
		||||
            class="last-message flex items-center color-[#989EA6]"
 | 
			
		||||
          ></div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="kefu-conversation-right color-[#989EA6]">
 | 
			
		||||
        {{ formatDate(item.lastMessageTime) }}
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { KeFuConversationApi, KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation'
 | 
			
		||||
import { replaceEmoji } from '@/views/mall/promotion/kefu/components/emoji'
 | 
			
		||||
import { formatDate, getNowDateTime } from '@/utils/formatTime'
 | 
			
		||||
 | 
			
		||||
defineOptions({ name: 'KeFuConversationBox' })
 | 
			
		||||
const activeConversationIndex = ref(0) // 默认激活第一个
 | 
			
		||||
const conversationList = ref<KeFuConversationRespVO[]>([]) // 会话列表
 | 
			
		||||
const getConversationList = async () => {
 | 
			
		||||
  conversationList.value = await KeFuConversationApi.getConversationList()
 | 
			
		||||
  // 测试数据
 | 
			
		||||
  for (let i = 0; i < 5; i++) {
 | 
			
		||||
    conversationList.value.push({
 | 
			
		||||
      id: 1,
 | 
			
		||||
      userId: 283,
 | 
			
		||||
      userAvatar:
 | 
			
		||||
        'https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTKMezSxtOImrC9lbhwHiazYwck3xwrEcO7VJfG6WQo260whaeVNoByE5RreiaGsGfOMlIiaDhSaA991w/132',
 | 
			
		||||
      nickname: '辉辉鸭' + i,
 | 
			
		||||
      lastMessageTime: getNowDateTime(),
 | 
			
		||||
      lastMessageContent: '[爱心][爱心]你好哇',
 | 
			
		||||
      lastMessageContentType: 1,
 | 
			
		||||
      adminPinned: false,
 | 
			
		||||
      userDeleted: false,
 | 
			
		||||
      adminDeleted: false,
 | 
			
		||||
      adminUnreadMessageCount: 19
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
defineExpose({ getConversationList })
 | 
			
		||||
const emits = defineEmits<{
 | 
			
		||||
  (e: 'change', v: number): void
 | 
			
		||||
}>()
 | 
			
		||||
// 打开右侧消息
 | 
			
		||||
const openRightMessage = (item: KeFuConversationRespVO, index: number) => {
 | 
			
		||||
  activeConversationIndex.value = index
 | 
			
		||||
  emits('change', item.id)
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.kefu {
 | 
			
		||||
  &-conversation {
 | 
			
		||||
    height: 60px;
 | 
			
		||||
    padding: 10px;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    transition: border-left 0.05s ease-in-out; /* 设置过渡效果 */
 | 
			
		||||
 | 
			
		||||
    &-left {
 | 
			
		||||
      .last-message {
 | 
			
		||||
        width: 300px;
 | 
			
		||||
        overflow: hidden; // 隐藏超出的文本
 | 
			
		||||
        white-space: nowrap; // 禁止换行
 | 
			
		||||
        text-overflow: ellipsis; // 添加省略号
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .active {
 | 
			
		||||
    border-left: 5px #3271ff solid;
 | 
			
		||||
    background-color: #eff0f1;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										77
									
								
								src/views/mall/promotion/kefu/components/KefuChatBox.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/views/mall/promotion/kefu/components/KefuChatBox.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <el-container class="kefu">
 | 
			
		||||
    <el-header>
 | 
			
		||||
      <div class="kefu-title">芋道</div>
 | 
			
		||||
    </el-header>
 | 
			
		||||
    <el-main class="kefu-content">
 | 
			
		||||
      <div
 | 
			
		||||
        v-for="item in 100"
 | 
			
		||||
        :key="item"
 | 
			
		||||
        :class="[item % 2 === 0 ? `ss-row-left` : `ss-row-right`]"
 | 
			
		||||
        class="flex mb-20px w-[100%]"
 | 
			
		||||
      >
 | 
			
		||||
        <el-avatar
 | 
			
		||||
          v-if="item % 2 === 0"
 | 
			
		||||
          alt="avatar"
 | 
			
		||||
          src="https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"
 | 
			
		||||
        />
 | 
			
		||||
        <div class="ml-10px"> Lorem Ipsum,也称乱数假文或者哑元文本</div>
 | 
			
		||||
        <el-avatar
 | 
			
		||||
          v-if="item % 2 !== 0"
 | 
			
		||||
          alt="avatar"
 | 
			
		||||
          src="https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"
 | 
			
		||||
        />
 | 
			
		||||
      </div>
 | 
			
		||||
    </el-main>
 | 
			
		||||
    <el-footer height="230px">
 | 
			
		||||
      <div class="h-[100%]">
 | 
			
		||||
        <div class="chat-tools">
 | 
			
		||||
          <Icon :size="30" class="ml-10px" icon="fa:frown-o" />
 | 
			
		||||
        </div>
 | 
			
		||||
        <el-input v-model="message" :autosize="{ minRows: 6, maxRows: 6 }" type="textarea" />
 | 
			
		||||
        <div class="h-45px flex justify-end">
 | 
			
		||||
          <el-button class="mt-10px" type="primary">发送</el-button>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </el-footer>
 | 
			
		||||
  </el-container>
 | 
			
		||||
  <!-- 没选择左侧会话时显示空界面 -->
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
defineOptions({ name: 'KeFuMessageBox' })
 | 
			
		||||
const message = ref('')
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.kefu {
 | 
			
		||||
  &-title {
 | 
			
		||||
    border-bottom: #e4e0e0 solid 1px;
 | 
			
		||||
    height: 60px;
 | 
			
		||||
    line-height: 60px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &-content {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .chat-tools {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    border: #e4e0e0 solid 1px;
 | 
			
		||||
    height: 44px;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .ss-row-left {
 | 
			
		||||
    justify-content: flex-start;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .ss-row-right {
 | 
			
		||||
    justify-content: flex-end;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep(textarea) {
 | 
			
		||||
    resize: none;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										14
									
								
								src/views/mall/promotion/kefu/components/constants.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/views/mall/promotion/kefu/components/constants.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
export const KeFuMessageContentTypeEnum = {
 | 
			
		||||
  TEXT: 1, // 文本消息
 | 
			
		||||
  IMAGE: 2, // 图片消息
 | 
			
		||||
  VOICE: 3, // 语音消息
 | 
			
		||||
  VIDEO: 4, // 视频消息
 | 
			
		||||
  SYSTEM: 5, // 系统消息
 | 
			
		||||
  // ========== 商城特殊消息 ==========
 | 
			
		||||
  PRODUCT: 10, //  商品消息
 | 
			
		||||
  ORDER: 11 //  订单消息"
 | 
			
		||||
}
 | 
			
		||||
export const UserTypeEnum = {
 | 
			
		||||
  MEMBER: 1, // 会员 面向 c 端,普通用户
 | 
			
		||||
  ADMIN: 2 // 管理员 面向 b 端,管理后台
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										91
									
								
								src/views/mall/promotion/kefu/components/emoji.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								src/views/mall/promotion/kefu/components/emoji.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
			
		||||
export const emojiList = [
 | 
			
		||||
  { name: '[笑掉牙]', file: 'xiaodiaoya.png' },
 | 
			
		||||
  { name: '[可爱]', file: 'keai.png' },
 | 
			
		||||
  { name: '[冷酷]', file: 'lengku.png' },
 | 
			
		||||
  { name: '[闭嘴]', file: 'bizui.png' },
 | 
			
		||||
  { name: '[生气]', file: 'shengqi.png' },
 | 
			
		||||
  { name: '[惊恐]', file: 'jingkong.png' },
 | 
			
		||||
  { name: '[瞌睡]', file: 'keshui.png' },
 | 
			
		||||
  { name: '[大笑]', file: 'daxiao.png' },
 | 
			
		||||
  { name: '[爱心]', file: 'aixin.png' },
 | 
			
		||||
  { name: '[坏笑]', file: 'huaixiao.png' },
 | 
			
		||||
  { name: '[飞吻]', file: 'feiwen.png' },
 | 
			
		||||
  { name: '[疑问]', file: 'yiwen.png' },
 | 
			
		||||
  { name: '[开心]', file: 'kaixin.png' },
 | 
			
		||||
  { name: '[发呆]', file: 'fadai.png' },
 | 
			
		||||
  { name: '[流泪]', file: 'liulei.png' },
 | 
			
		||||
  { name: '[汗颜]', file: 'hanyan.png' },
 | 
			
		||||
  { name: '[惊悚]', file: 'jingshu.png' },
 | 
			
		||||
  { name: '[困~]', file: 'kun.png' },
 | 
			
		||||
  { name: '[心碎]', file: 'xinsui.png' },
 | 
			
		||||
  { name: '[天使]', file: 'tianshi.png' },
 | 
			
		||||
  { name: '[晕]', file: 'yun.png' },
 | 
			
		||||
  { name: '[啊]', file: 'a.png' },
 | 
			
		||||
  { name: '[愤怒]', file: 'fennu.png' },
 | 
			
		||||
  { name: '[睡着]', file: 'shuizhuo.png' },
 | 
			
		||||
  { name: '[面无表情]', file: 'mianwubiaoqing.png' },
 | 
			
		||||
  { name: '[难过]', file: 'nanguo.png' },
 | 
			
		||||
  { name: '[犯困]', file: 'fankun.png' },
 | 
			
		||||
  { name: '[好吃]', file: 'haochi.png' },
 | 
			
		||||
  { name: '[呕吐]', file: 'outu.png' },
 | 
			
		||||
  { name: '[龇牙]', file: 'ziya.png' },
 | 
			
		||||
  { name: '[懵比]', file: 'mengbi.png' },
 | 
			
		||||
  { name: '[白眼]', file: 'baiyan.png' },
 | 
			
		||||
  { name: '[饿死]', file: 'esi.png' },
 | 
			
		||||
  { name: '[凶]', file: 'xiong.png' },
 | 
			
		||||
  { name: '[感冒]', file: 'ganmao.png' },
 | 
			
		||||
  { name: '[流汗]', file: 'liuhan.png' },
 | 
			
		||||
  { name: '[笑哭]', file: 'xiaoku.png' },
 | 
			
		||||
  { name: '[流口水]', file: 'liukoushui.png' },
 | 
			
		||||
  { name: '[尴尬]', file: 'ganga.png' },
 | 
			
		||||
  { name: '[惊讶]', file: 'jingya.png' },
 | 
			
		||||
  { name: '[大惊]', file: 'dajing.png' },
 | 
			
		||||
  { name: '[不好意思]', file: 'buhaoyisi.png' },
 | 
			
		||||
  { name: '[大闹]', file: 'danao.png' },
 | 
			
		||||
  { name: '[不可思议]', file: 'bukesiyi.png' },
 | 
			
		||||
  { name: '[爱你]', file: 'aini.png' },
 | 
			
		||||
  { name: '[红心]', file: 'hongxin.png' },
 | 
			
		||||
  { name: '[点赞]', file: 'dianzan.png' },
 | 
			
		||||
  { name: '[恶魔]', file: 'emo.png' }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
export const emojiPage = {}
 | 
			
		||||
emojiList.forEach((item, index) => {
 | 
			
		||||
  if (!emojiPage[Math.floor(index / 30) + 1]) {
 | 
			
		||||
    emojiPage[Math.floor(index / 30) + 1] = []
 | 
			
		||||
  }
 | 
			
		||||
  emojiPage[Math.floor(index / 30) + 1].push(item)
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// 后端上传地址
 | 
			
		||||
const staticUrl = import.meta.env.VITE_STATIC_URL
 | 
			
		||||
 | 
			
		||||
// 处理表情
 | 
			
		||||
export function replaceEmoji(data: string) {
 | 
			
		||||
  let newData = data
 | 
			
		||||
  if (typeof newData !== 'object') {
 | 
			
		||||
    const reg = /\[(.+?)\]/g // [] 中括号
 | 
			
		||||
    const zhEmojiName = newData.match(reg)
 | 
			
		||||
    if (zhEmojiName) {
 | 
			
		||||
      zhEmojiName.forEach((item) => {
 | 
			
		||||
        const emojiFile = selEmojiFile(item)
 | 
			
		||||
        newData = newData.replace(
 | 
			
		||||
          item,
 | 
			
		||||
          `<img class="chat-img" style="width: 24px;height: 24px;margin: 0 3px;" src="${
 | 
			
		||||
            staticUrl + '/static/img/chat/emoji/' + emojiFile
 | 
			
		||||
          }"/>`
 | 
			
		||||
        )
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return newData
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function selEmojiFile(name: string) {
 | 
			
		||||
  for (const index in emojiList) {
 | 
			
		||||
    if (emojiList[index].name === name) {
 | 
			
		||||
      return emojiList[index].file
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return false
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								src/views/mall/promotion/kefu/components/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/views/mall/promotion/kefu/components/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
import KeFuConversationBox from './KeFuConversationBox.vue'
 | 
			
		||||
import KeFuChatBox from './KefuChatBox.vue'
 | 
			
		||||
import * as Constants from './constants'
 | 
			
		||||
 | 
			
		||||
export { KeFuConversationBox, KeFuChatBox, Constants }
 | 
			
		||||
							
								
								
									
										55
									
								
								src/views/mall/promotion/kefu/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/views/mall/promotion/kefu/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <el-row :gutter="10">
 | 
			
		||||
    <el-col :span="8">
 | 
			
		||||
      <ContentWrap>
 | 
			
		||||
        <KeFuConversationBox ref="keFuConversationRef" @change="handleChange" />
 | 
			
		||||
      </ContentWrap>
 | 
			
		||||
    </el-col>
 | 
			
		||||
    <el-col :span="16">
 | 
			
		||||
      <ContentWrap>
 | 
			
		||||
        <KeFuChatBox ref="keFuChatBoxRef" />
 | 
			
		||||
      </ContentWrap>
 | 
			
		||||
    </el-col>
 | 
			
		||||
  </el-row>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { KeFuChatBox, KeFuConversationBox } from './components'
 | 
			
		||||
 | 
			
		||||
defineOptions({ name: 'KeFu' })
 | 
			
		||||
 | 
			
		||||
const keFuChatBoxRef = ref<InstanceType<typeof KeFuChatBox>>()
 | 
			
		||||
const handleChange = () => {}
 | 
			
		||||
 | 
			
		||||
const keFuConversationRef = ref<InstanceType<typeof KeFuConversationBox>>()
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  keFuConversationRef.value?.getConversationList()
 | 
			
		||||
})
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
.kefu {
 | 
			
		||||
  height: calc(100vh - 165px);
 | 
			
		||||
  overflow: auto; /* 确保内容可滚动 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 定义滚动条样式 */
 | 
			
		||||
::-webkit-scrollbar {
 | 
			
		||||
  width: 10px;
 | 
			
		||||
  height: 6px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*定义滚动条轨道 内阴影+圆角*/
 | 
			
		||||
::-webkit-scrollbar-track {
 | 
			
		||||
  box-shadow: inset 0 0 0px rgba(240, 240, 240, 0.5);
 | 
			
		||||
  border-radius: 10px;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*定义滑块 内阴影+圆角*/
 | 
			
		||||
::-webkit-scrollbar-thumb {
 | 
			
		||||
  border-radius: 10px;
 | 
			
		||||
  box-shadow: inset 0 0 0px rgba(240, 240, 240, 0.5);
 | 
			
		||||
  background-color: rgba(240, 240, 240, 0.5);
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										1
									
								
								types/env.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								types/env.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -19,6 +19,7 @@ interface ImportMetaEnv {
 | 
			
		||||
  readonly VITE_UPLOAD_URL: string
 | 
			
		||||
  readonly VITE_API_URL: string
 | 
			
		||||
  readonly VITE_BASE_PATH: string
 | 
			
		||||
  readonly VITE_STATIC_URL: string
 | 
			
		||||
  readonly VITE_DROP_DEBUGGER: string
 | 
			
		||||
  readonly VITE_DROP_CONSOLE: string
 | 
			
		||||
  readonly VITE_SOURCEMAP: string
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user