Răsfoiți Sursa

客服卡片修改

Zhangbw 2 luni în urmă
părinte
comite
4d9b593e17

+ 2 - 1
.claude/settings.local.json

@@ -7,7 +7,8 @@
       "Bash(findstr:*)",
       "Bash(dir:*)",
       "Read(//d/program/**)",
-      "Bash(tree:*)"
+      "Bash(tree:*)",
+      "Bash(git checkout:*)"
     ],
     "additionalDirectories": [
       "d:\\program\\AI-TALK\\ruoyi-modules\\yp-talk",

+ 266 - 115
src/CustomerService.vue

@@ -23,33 +23,19 @@
                 <el-form label-position="top" size="default">
                   <el-form-item label="语言">
                     <el-select v-model="config.language" style="width: 100%">
-                      <el-option label="中文" value="中文" />
-                    </el-select>
-                  </el-form-item>
-
-                  <el-form-item label="TTS">
-                    <el-select v-model="config.tts" style="width: 100%">
-                      <el-option label="Minimax" value="Minimax" />
+                      <el-option
+                        v-for="item in languageOptions"
+                        :key="item.dictValue"
+                        :label="item.dictLabel"
+                        :value="item.dictValue"
+                      />
                     </el-select>
                   </el-form-item>
 
                   <el-form-item label="背景音">
-                    <el-select v-model="config.bgSound" style="width: 100%">
-                      <el-option label="客服中心" value="客服中心" />
-                    </el-select>
-                  </el-form-item>
-
-                  <el-form-item label="断句模式">
-                    <el-radio-group v-model="config.punctuation" style="width: 100%">
-                      <el-radio-button value="semantic">语义断句</el-radio-button>
-                      <el-radio-button value="normal">普通断句</el-radio-button>
-                    </el-radio-group>
-                  </el-form-item>
-
-                  <el-form-item label="打断模式">
-                    <el-radio-group v-model="config.interrupt" style="width: 100%">
-                      <el-radio-button value="smart">智能打断</el-radio-button>
-                      <el-radio-button value="manual">手动打断</el-radio-button>
+                    <el-radio-group v-model="config.bgSoundEnabled">
+                      <el-radio-button :value="true">开启</el-radio-button>
+                      <el-radio-button :value="false">关闭</el-radio-button>
                     </el-radio-group>
                   </el-form-item>
                 </el-form>
@@ -66,31 +52,45 @@
               </div>
               <div v-if="otherExpanded" class="collapse-content">
                 <el-form label-position="top" size="default">
-                  <el-form-item label="打断时长">
-                    <div class="slider-value">{{ config.interruptTime }}ms</div>
+                  <el-form-item label="语速" class="compact-slider">
+                    <div class="slider-value">{{ config.speed }}</div>
+                    <el-slider
+                      v-model="config.speed"
+                      :min="0"
+                      :max="100"
+                      :step="1"
+                    />
+                    <div class="slider-labels">
+                      <span>慢</span>
+                      <span>快</span>
+                    </div>
+                  </el-form-item>
+
+                  <el-form-item label="音调" class="compact-slider">
+                    <div class="slider-value">{{ config.pitch }}</div>
                     <el-slider
-                      v-model="config.interruptTime"
-                      :min="100"
-                      :max="500"
-                      :step="10"
+                      v-model="config.pitch"
+                      :min="0"
+                      :max="100"
+                      :step="1"
                     />
                     <div class="slider-labels">
-                      <span>更灵敏</span>
-                      <span>更稳定</span>
+                      <span></span>
+                      <span></span>
                     </div>
                   </el-form-item>
 
-                  <el-form-item label="VAD 时长">
-                    <div class="slider-value">{{ config.vadTime }}ms</div>
+                  <el-form-item label="音量" class="compact-slider">
+                    <div class="slider-value">{{ config.volume }}</div>
                     <el-slider
-                      v-model="config.vadTime"
-                      :min="100"
-                      :max="800"
-                      :step="10"
+                      v-model="config.volume"
+                      :min="0"
+                      :max="100"
+                      :step="1"
                     />
                     <div class="slider-labels">
-                      <span>更快</span>
-                      <span>更慢</span>
+                      <span></span>
+                      <span></span>
                     </div>
                   </el-form-item>
                 </el-form>
@@ -108,7 +108,8 @@
                   :class="{ selected: selectedAgent === agent.id }"
                   @click="selectedAgent = agent.id"
                 >
-                  <div class="avatar" :class="agent.gender"></div>
+                  <img v-if="agent.avatarUrl" :src="getAvatarUrl(agent.avatarUrl)" class="avatar-img" />
+                  <div v-else class="avatar" :class="agent.gender"></div>
                   <div class="gender-icon" :class="agent.gender">{{ agent.gender === 'female' ? '♀' : '♂' }}</div>
                   <div class="agent-name">{{ agent.name }}</div>
                 </div>
@@ -124,7 +125,7 @@
               </div>
             </div>
             <div class="agents-footer">
-              <el-button type="primary" round size="large" class="start-btn" @click="showChat = true">
+              <el-button type="primary" round size="large" class="start-btn" @click="startChat">
                 开始对话
               </el-button>
             </div>
@@ -132,7 +133,7 @@
 
           <main class="right-panel chat-panel" v-else>
             <!-- 对话历史 -->
-            <div class="chat-content">
+            <div class="chat-content" ref="chatContent">
               <div
                 v-for="(msg, index) in chatHistory"
                 :key="index"
@@ -192,7 +193,7 @@
 </template>
 
 <script setup>
-import { ref, computed, watch } from 'vue'
+import { ref, computed, watch, nextTick, onMounted } from 'vue'
 import { ArrowUp, ArrowDown, Microphone, PhoneFilled, ChatDotRound, Mute } from '@element-plus/icons-vue'
 import { useVoiceRecognition } from './composables/useVoiceRecognition.js'
 import { ElMessage } from 'element-plus'
@@ -204,6 +205,8 @@ const sidebarVisible = ref(true)
 const basicExpanded = ref(true)
 const otherExpanded = ref(false)
 const currentPage = ref(0)
+const chatContent = ref(null)
+const languageOptions = ref([])
 
 // 语音识别
 const { isRecording, currentTranscription, tempTranscription, startRecording, stopRecording } = useVoiceRecognition()
@@ -216,16 +219,6 @@ const playAudio = (base64Audio) => {
       return
     }
 
-    console.log('音频数据长度:', base64Audio.length)
-    console.log('音频数据前100字符:', base64Audio.substring(0, 100))
-    console.log('音频数据后100字符:', base64Audio.substring(base64Audio.length - 100))
-
-    // 检查是否有中间的=号
-    const middlePart = base64Audio.substring(100, base64Audio.length - 100)
-    if (middlePart.includes('=')) {
-      console.log('发现中间有=号,位置:', base64Audio.indexOf('=', 100))
-    }
-
     const audioData = atob(base64Audio)
     const arrayBuffer = new ArrayBuffer(audioData.length)
     const view = new Uint8Array(arrayBuffer)
@@ -259,6 +252,15 @@ const playAudio = (base64Audio) => {
 // 对话历史
 const chatHistory = ref([])
 
+// 滚动到底部
+const scrollToBottom = () => {
+  nextTick(() => {
+    if (chatContent.value) {
+      chatContent.value.scrollTop = chatContent.value.scrollHeight
+    }
+  })
+}
+
 // 波形数据
 const waveformData = ref(Array(60).fill(20))
 let waveformInterval = null
@@ -272,6 +274,11 @@ const updateWaveform = () => {
 
 // 监听转写结果变化,当有确定性结果时添加到对话历史
 watch(currentTranscription, async (newVal, oldVal) => {
+  // 只有在录音状态下才处理语音识别结果
+  if (!isRecording.value || isMicMuted.value) {
+    return
+  }
+
   if (newVal && newVal !== oldVal && newVal.length > oldVal.length) {
     const newContent = newVal.slice(oldVal.length).trim()
     if (newContent) {
@@ -280,6 +287,7 @@ watch(currentTranscription, async (newVal, oldVal) => {
         type: 'user',
         content: newContent
       })
+      scrollToBottom()
 
       // 发送到后端处理
       try {
@@ -294,19 +302,14 @@ watch(currentTranscription, async (newVal, oldVal) => {
           })
         })
 
-        // 检查原始响应
-        const responseText = await response.text()
-        console.log('原始响应文本长度:', responseText.length)
-        console.log('原始响应前200字符:', responseText.substring(0, 200))
-
-        const data = JSON.parse(responseText)
-        console.log('解析后的audio字段长度:', data.audio ? data.audio.length : 0)
+        const data = await response.json()
 
         // 添加客服回复
         chatHistory.value.push({
           type: 'agent',
           content: data.reply
         })
+        scrollToBottom()
 
         // 播放语音
         if (data.audio) {
@@ -329,12 +332,6 @@ watch(showChat, async (newVal) => {
 
       // 启动波形动画
       waveformInterval = setInterval(updateWaveform, 100)
-
-      // 添加欢迎消息
-      chatHistory.value = [{
-        type: 'agent',
-        content: '你好,我是你的智能客服助手!请开始说话...'
-      }]
     } catch (error) {
       ElMessage.error('启动语音识别失败: ' + error.message)
     }
@@ -347,12 +344,34 @@ watch(showChat, async (newVal) => {
   }
 })
 
+// 监听输入方式切换
+watch(isTextInput, async (newVal) => {
+  if (newVal && isRecording.value) {
+    // 切换到文本输入时停止语音识别
+    stopRecording()
+    isMicMuted.value = true
+    if (waveformInterval) {
+      clearInterval(waveformInterval)
+      waveformInterval = null
+    }
+  } else if (!newVal && !isRecording.value && showChat.value) {
+    // 切换回语音模式时重新启动语音识别
+    try {
+      await startRecording()
+      isMicMuted.value = false
+      waveformInterval = setInterval(updateWaveform, 100)
+    } catch (error) {
+      ElMessage.error('启动语音识别失败: ' + error.message)
+    }
+  }
+})
+
 // 切换麦克风静音状态
 const toggleMic = () => {
   if (isRecording.value) {
     // 当前正在录音,点击后停止并静音
-    stopRecording()
     isMicMuted.value = true
+    stopRecording()
     if (waveformInterval) {
       clearInterval(waveformInterval)
       waveformInterval = null
@@ -384,6 +403,7 @@ const sendTextMessage = async () => {
     type: 'user',
     content: content
   })
+  scrollToBottom()
 
   // 清空输入框
   textMessage.value = ''
@@ -401,12 +421,7 @@ const sendTextMessage = async () => {
       })
     })
 
-    // 检查原始响应
-    const responseText = await response.text()
-    console.log('原始响应文本长度:', responseText.length)
-    console.log('原始响应前200字符:', responseText.substring(0, 200))
-
-    const data = JSON.parse(responseText)
+    const data = await response.json()
     console.log('解析后的audio字段长度:', data.audio ? data.audio.length : 0)
 
     // 添加客服回复
@@ -414,6 +429,7 @@ const sendTextMessage = async () => {
       type: 'agent',
       content: data.reply
     })
+    scrollToBottom()
 
     // 播放语音
     if (data.audio) {
@@ -425,40 +441,142 @@ const sendTextMessage = async () => {
   }
 }
 
-const agents = ref([
-  { id: 1, name: '客服 001 号', gender: 'female' },
-  { id: 2, name: '客服 002 号', gender: 'male' },
-  { id: 3, name: '客服 003 号', gender: 'female' },
-  { id: 4, name: '客服 004 号', gender: 'male' },
-  { id: 5, name: '客服 005 号', gender: 'female' },
-  { id: 6, name: '客服 006 号', gender: 'male' },
-  { id: 7, name: '客服 007 号', gender: 'female' },
-  { id: 8, name: '客服 008 号', gender: 'male' },
-  { id: 9, name: '客服 009 号', gender: 'female' },
-  { id: 10, name: '客服 010 号', gender: 'male' },
-  { id: 11, name: '客服 011 号', gender: 'female' },
-  { id: 12, name: '客服 012 号', gender: 'male' },
-  { id: 13, name: '客服 013 号', gender: 'female' },
-  { id: 14, name: '客服 014 号', gender: 'male' },
-  { id: 15, name: '客服 015 号', gender: 'female' },
-  { id: 16, name: '客服 016 号', gender: 'male' },
-  { id: 17, name: '客服 017 号', gender: 'female' },
-  { id: 18, name: '客服 018 号', gender: 'male' },
-  { id: 19, name: '客服 019 号', gender: 'female' },
-  { id: 20, name: '客服 020 号', gender: 'male' }
-])
+const agents = ref([])
 
 const config = ref({
-  language: '中文',
-  tts: 'Minimax',
-  bgSound: '客服中心',
-  punctuation: 'semantic',
-  interrupt: 'smart',
-  interruptTime: 200,
-  vadTime: 400
+  language: 'zh',
+  bgSoundEnabled: false,
+  speed: 50,
+  pitch: 50,
+  volume: 50
+})
+
+const selectedAgent = ref(null)
+
+// 获取客服列表
+const fetchAgents = async () => {
+  try {
+    const response = await fetch('http://localhost:8080/talk/agent/list?status=0')
+    const result = await response.json()
+    if (result.code === 200 && result.rows) {
+      agents.value = result.rows.map(agent => ({
+        id: agent.id,
+        name: agent.name,
+        gender: agent.gender === '0' ? 'male' : 'female',
+        avatarUrl: agent.avatarUrl,
+        greetingMessage: agent.greetingMessage,
+        ttsVcn: agent.ttsVcn,
+        ttsSpeed: agent.ttsSpeed,
+        ttsPitch: agent.ttsPitch,
+        ttsVolume: agent.ttsVolume,
+        ttsBgs: agent.ttsBgs,
+        language: agent.language
+      }))
+      if (agents.value.length > 0) {
+        selectedAgent.value = agents.value[0].id
+      }
+    }
+  } catch (error) {
+    console.error('获取客服列表失败:', error)
+    ElMessage.error('获取客服列表失败')
+  }
+}
+
+// 获取语言字典
+const fetchLanguageOptions = async () => {
+  try {
+    const response = await fetch('http://localhost:8080/talk/dict/language')
+    const data = await response.json()
+    languageOptions.value = data
+  } catch (error) {
+    console.error('获取语言选项失败:', error)
+    ElMessage.error('获取语言选项失败')
+  }
+}
+
+// 组件挂载时获取语言选项和客服列表
+onMounted(() => {
+  fetchLanguageOptions()
+  fetchAgents()
 })
 
-const selectedAgent = ref(1)
+// 获取头像完整URL
+const getAvatarUrl = (avatarUrl) => {
+  if (!avatarUrl) return ''
+  if (avatarUrl.startsWith('http://') || avatarUrl.startsWith('https://')) {
+    return avatarUrl
+  }
+  return 'http://localhost:8080' + avatarUrl
+}
+
+// 开始对话
+const startChat = async () => {
+  if (!selectedAgent.value) {
+    ElMessage.warning('请先选择一个客服')
+    return
+  }
+
+  try {
+    // 更新客服配置
+    const selectedAgentData = agents.value.find(a => a.id === selectedAgent.value)
+    if (selectedAgentData) {
+      const response = await fetch('http://localhost:8080/talk/agent/' + selectedAgent.value, {
+        method: 'PUT',
+        headers: {
+          'Content-Type': 'application/json'
+        },
+        body: JSON.stringify({
+          id: selectedAgent.value,
+          ttsSpeed: config.value.speed,
+          ttsPitch: config.value.pitch,
+          ttsVolume: config.value.volume,
+          ttsBgs: config.value.bgSoundEnabled ? 1 : 0,
+          language: config.value.language
+        })
+      })
+
+      if (response.ok) {
+        console.log('客服配置已更新')
+      }
+
+      // 显示欢迎语并转语音
+      if (selectedAgentData.greetingMessage) {
+        chatHistory.value = [{
+          type: 'agent',
+          content: selectedAgentData.greetingMessage
+        }]
+
+        // 调用后端生成欢迎语语音
+        try {
+          const ttsResponse = await fetch('http://localhost:8080/talk/message', {
+            method: 'POST',
+            headers: {
+              'Content-Type': 'application/json'
+            },
+            body: JSON.stringify({
+              message: selectedAgentData.greetingMessage,
+              agentId: selectedAgent.value,
+              isGreeting: true
+            })
+          })
+
+          const ttsData = await ttsResponse.json()
+          if (ttsData.audio) {
+            playAudio(ttsData.audio)
+          }
+        } catch (error) {
+          console.error('生成欢迎语语音失败:', error)
+        }
+      } else {
+        chatHistory.value = []
+      }
+    }
+  } catch (error) {
+    console.error('更新客服配置失败:', error)
+  }
+
+  showChat.value = true
+}
 
 const pageSize = 6
 const totalPages = computed(() => Math.ceil(agents.value.length / pageSize))
@@ -805,10 +923,21 @@ const handleWheel = (e) => {
 }
 
 .avatar {
-  width: 45px;
-  height: 45px;
+  width: 120px;
+  height: 120px;
   border-radius: 50%;
-  margin: 0 auto 6px;
+  margin: 20px auto 12px;
+  border: 3px solid #e5e7eb;
+}
+
+.avatar-img {
+  width: 120px;
+  height: 120px;
+  border-radius: 50%;
+  margin: 20px auto 12px;
+  object-fit: cover;
+  border: 3px solid #e5e7eb;
+  background: #f9fafb;
 }
 
 .avatar.female {
@@ -821,17 +950,19 @@ const handleWheel = (e) => {
 
 .gender-icon {
   position: absolute;
-  top: 42px;
-  right: calc(50% - 26px);
-  width: 16px;
-  height: 16px;
+  top: 110px;
+  right: calc(50% - 70px);
+  width: 28px;
+  height: 28px;
   border-radius: 50%;
   display: flex;
   align-items: center;
   justify-content: center;
   color: white;
-  font-weight: 600;
-  font-size: 9px;
+  font-weight: 700;
+  font-size: 14px;
+  border: 2px solid white;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
 }
 
 .gender-icon.female {
@@ -843,9 +974,10 @@ const handleWheel = (e) => {
 }
 
 .agent-name {
-  font-size: 12px;
+  font-size: 14px;
   color: #1f2937;
-  font-weight: 500;
+  font-weight: 600;
+  margin-top: 8px;
 }
 
 .start-btn {
@@ -895,7 +1027,26 @@ const handleWheel = (e) => {
   justify-content: space-between;
   font-size: 12px;
   color: #9ca3af;
-  margin-top: 4px;
+  margin-top: 2px;
+  width: 100%;
+}
+
+/* 紧凑型滑块样式 */
+.compact-slider {
+  margin-bottom: 12px;
+}
+
+.compact-slider :deep(.el-form-item__label) {
+  margin-bottom: 0px;
+  padding-bottom: 0;
+}
+
+.compact-slider .slider-value {
+  margin-bottom: 0px;
+}
+
+.compact-slider :deep(.el-form-item__content) {
+  width: 100%;
 }
 
 /* 自定义折叠组件样式 */

+ 3 - 3
src/composables/useVoiceRecognition.js

@@ -3,9 +3,9 @@ import CryptoJS from 'crypto-js'
 
 // 科大讯飞配置
 const XFYUN_CONFIG = {
-  APPID: '8aec56da',
-  ACCESS_KEY_ID: 'e464b3db963d9c9b3d10863cf716e1e7',
-  ACCESS_KEY_SECRET: 'NjBhODAwNzQ4NDI4ZDE3NWIwZWE4NzVi',
+  APPID: '0b53c170',
+  ACCESS_KEY_ID: '3915b5e04c7e118fea615889a1c94794',
+  ACCESS_KEY_SECRET: 'ZTZjZmU3YzczMjdmNmQwMTc0ZDU3OTEw',
   API_URL: 'wss://office-api-ast-dx.iflyaisol.com/ast/communicate/v1'
 }
 

+ 6 - 33
target/classes/META-INF/mps/autoMapper

@@ -1,34 +1,7 @@
+org.dromara.workflow.domain.vo.FlowCategoryVo
+org.dromara.workflow.domain.vo.TestLeaveVo
 org.dromara.web.domain.vo.TenantListVo
-org.dromara.system.domain.bo.SysLogininforBo
-org.dromara.system.domain.vo.SysNoticeVo
-org.dromara.system.domain.bo.SysDictDataBo
-org.dromara.system.domain.bo.SysNoticeBo
-org.dromara.system.domain.vo.SysClientVo
-org.dromara.system.domain.vo.SysConfigVo
-org.dromara.system.domain.bo.SysOssBo
-org.dromara.system.domain.vo.SysMenuVo
-org.dromara.system.domain.vo.SysUserVo
-org.dromara.system.domain.vo.SysDeptVo
-org.dromara.system.domain.bo.SysDictTypeBo
-org.dromara.system.domain.bo.SysTenantBo
-org.dromara.system.domain.bo.SysOssConfigBo
-org.dromara.system.domain.bo.SysMenuBo
-org.dromara.system.domain.bo.SysDeptBo
-org.dromara.system.domain.vo.SysOperLogVo
-org.dromara.system.domain.vo.SysOssConfigVo
-org.dromara.system.domain.vo.SysLogininforVo
-org.dromara.system.domain.bo.SysSocialBo
-org.dromara.system.domain.bo.SysTenantPackageBo
-org.dromara.system.domain.vo.SysDictTypeVo
-org.dromara.system.domain.bo.SysUserBo
-org.dromara.system.domain.vo.SysOssVo
-org.dromara.system.domain.vo.SysTenantPackageVo
-org.dromara.system.domain.vo.SysSocialVo
-org.dromara.system.domain.vo.SysTenantVo
-org.dromara.system.domain.vo.SysRoleVo
-org.dromara.system.domain.vo.SysDictDataVo
-org.dromara.system.domain.bo.SysPostBo
-org.dromara.system.domain.bo.SysRoleBo
-org.dromara.system.domain.bo.SysClientBo
-org.dromara.system.domain.bo.SysConfigBo
-org.dromara.system.domain.vo.SysPostVo
+org.dromara.workflow.domain.bo.TestLeaveBo
+org.dromara.workflow.domain.vo.FlowSpelVo
+org.dromara.workflow.domain.bo.FlowSpelBo
+org.dromara.workflow.domain.bo.FlowCategoryBo

+ 1 - 54
target/classes/META-INF/mps/mappers

@@ -1,55 +1,2 @@
-org.dromara.system.domain.vo.SysSocialVoToSysSocialMapper
-org.dromara.system.domain.vo.SysDictDataVoToSysDictDataMapper
-org.dromara.system.domain.SysOssConfigToSysOssConfigVoMapper
-org.dromara.system.domain.vo.SysLogininforVoToSysLogininforMapper
-org.dromara.system.domain.bo.SysConfigBoToSysConfigMapper
-org.dromara.system.domain.SysTenantPackageToSysTenantPackageVoMapper
-org.dromara.system.domain.bo.SysPostBoToSysPostMapper
-org.dromara.system.domain.vo.SysOssConfigVoToSysOssConfigMapper
-org.dromara.system.domain.SysUserToSysUserVoMapper
-org.dromara.system.domain.vo.SysDictTypeVoToSysDictTypeMapper
-org.dromara.system.domain.SysDictDataToSysDictDataVoMapper
-org.dromara.system.domain.bo.SysMenuBoToSysMenuMapper
-org.dromara.system.domain.vo.SysRoleVoToSysRoleMapper
-org.dromara.system.domain.vo.SysTenantVoToTenantListVoMapper
-org.dromara.system.domain.vo.SysClientVoToSysClientMapper
-org.dromara.system.domain.bo.SysOssConfigBoToSysOssConfigMapper
-org.dromara.system.domain.SysConfigToSysConfigVoMapper
-org.dromara.system.domain.bo.SysOperLogBoToOperLogEventMapper
-org.dromara.system.domain.bo.SysDeptBoToSysDeptMapper
-org.dromara.system.domain.vo.SysNoticeVoToSysNoticeMapper
-org.dromara.system.domain.bo.SysOssBoToSysOssMapper
-org.dromara.system.domain.vo.SysMenuVoToSysMenuMapper
-org.dromara.system.domain.SysMenuToSysMenuVoMapper
-org.dromara.system.domain.vo.SysTenantVoToSysTenantMapper
-org.dromara.system.domain.bo.SysUserBoToSysUserMapper
-org.dromara.system.domain.bo.SysClientBoToSysClientMapper
-org.dromara.system.domain.bo.SysDictDataBoToSysDictDataMapper
-org.dromara.system.domain.SysClientToSysClientVoMapper
-org.dromara.system.domain.vo.SysUserVoToSysUserMapper
-org.dromara.system.domain.SysNoticeToSysNoticeVoMapper
-org.dromara.system.domain.SysOssToSysOssVoMapper
-org.dromara.system.domain.SysOperLogToSysOperLogVoMapper
-org.dromara.system.domain.bo.SysLogininforBoToSysLogininforMapper
-org.dromara.system.domain.SysTenantToSysTenantVoMapper
-org.dromara.system.domain.vo.SysDeptVoToSysDeptMapper
-org.dromara.system.domain.vo.SysConfigVoToSysConfigMapper
-org.dromara.system.domain.bo.SysSocialBoToSysSocialMapper
-org.dromara.system.domain.bo.SysRoleBoToSysRoleMapper
-org.dromara.system.domain.vo.SysOssVoToSysOssMapper
-org.dromara.system.domain.SysDictTypeToSysDictTypeVoMapper
-org.dromara.system.domain.SysRoleToSysRoleVoMapper
-org.dromara.system.domain.vo.SysTenantPackageVoToSysTenantPackageMapper
-org.dromara.system.domain.bo.SysTenantBoToSysTenantMapper
-org.dromara.system.domain.bo.SysTenantPackageBoToSysTenantPackageMapper
-org.dromara.system.domain.SysLogininforToSysLogininforVoMapper
 org.dromara.web.domain.vo.TenantListVoToSysTenantVoMapper
-org.dromara.system.domain.vo.SysPostVoToSysPostMapper
-org.dromara.system.domain.SysSocialToSysSocialVoMapper
-org.dromara.system.domain.bo.SysDictTypeBoToSysDictTypeMapper
-org.dromara.common.log.event.OperLogEventToSysOperLogBoMapper
-org.dromara.system.domain.bo.SysOperLogBoToSysOperLogMapper
-org.dromara.system.domain.vo.SysOperLogVoToSysOperLogMapper
-org.dromara.system.domain.SysDeptToSysDeptVoMapper
-org.dromara.system.domain.bo.SysNoticeBoToSysNoticeMapper
-org.dromara.system.domain.SysPostToSysPostVoMapper
+org.dromara.system.domain.vo.SysTenantVoToTenantListVoMapper