模块取出

This commit is contained in:
2025-12-23 16:16:47 +08:00
parent 68daf391af
commit e75b2f3bab
22 changed files with 164 additions and 399 deletions

View File

@@ -46,40 +46,23 @@ declare module 'shared/components/ai/knowledge/DocumentDetail.vue' {
export default DocumentDetail
}
declare module 'shared/components/chatRoom/ChatRoom.vue' {
import { DefineComponent } from 'vue'
interface ChatMessageVO {
messageId: string
senderId: string
senderName: string
senderAvatar: string
content: string
files: string[]
sendTime: string
}
const ChatRoom: DefineComponent<{
messages: ChatMessageVO[]
currentUserId: string
roomName?: string
meetingUrl?: string
showMeeting?: boolean
fileDownloadUrl?: string
}, {}, {}, {}, {}, {}, {}, {
header?: () => any
'action-area'?: () => any
}>
export default ChatRoom
}
// ========== API 模块 ==========
declare module 'shared/api' {
export const api: any
import type { AxiosResponse, AxiosRequestConfig } from 'axios'
interface ApiInstance {
get<T = any>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>
post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>
put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>
delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>
uploadPut<T = any>(url: string, data: FormData, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>
}
export const api: ApiInstance
export const TokenManager: any
export const authAPI: any
export const fileAPI: any
export const workcaseAPI: any
}
declare module 'shared/api/auth' {
@@ -96,18 +79,9 @@ declare module 'shared/api/ai' {
export const aiChatAPI: any
}
declare module 'shared/api/workcase' {
export const workcaseAPI: any
export const workcaseChatAPI: any
}
// ============ types模块 ==================
declare module 'shared/types' {
import type { BaseDTO } from '../../../shared/src/types/base'
// 重新导出 base
export type { BaseDTO }
export type { BaseDTO, BaseVO } from '../../../shared/src/types/base'
// 重新导出 response
export type { ResultDomain } from '../../../shared/src/types/response'
@@ -138,39 +112,6 @@ declare module 'shared/types' {
CommentMessageParams
} from '../../../shared/src/types/ai'
// 重新导出 workcase
export type {
TbWorkcaseDTO,
TbWorkcaseProcessDTO,
TbWorkcaseDeviceDTO,
// 聊天室相关
TbChatRoomDTO,
TbChatRoomMessageDTO,
TbChatRoomMemberDTO,
TbVideoMeetingDTO,
TbMeetingParticipantDTO,
TbMeetingTranscriptionDTO,
ChatRoomVO,
ChatMessageVO,
ChatRoomMessageVO,
ChatMemberVO,
VideoMeetingVO,
MeetingParticipantVO,
SendMessageParam,
CreateMeetingParam,
MarkReadParam,
// 客服相关
TbCustomerServiceDTO,
CustomerServiceVO,
// 词云
TbWordCloudDTO,
// 来客相关
TbGuestDTO,
GuestVO,
CustomerVO,
ConversationVO
} from '../../../shared/src/types/workcase'
// 重新导出 menu
export type { MenuItem, toMenuItem, toMenuItems } from '../../../shared/src/types/menu'
}

View File

@@ -46,40 +46,23 @@ declare module 'shared/components/ai/knowledge/DocumentDetail.vue' {
export default DocumentDetail
}
declare module 'shared/components/chatRoom/ChatRoom.vue' {
import { DefineComponent } from 'vue'
interface ChatMessageVO {
messageId: string
senderId: string
senderName: string
senderAvatar: string
content: string
files: string[]
sendTime: string
}
const ChatRoom: DefineComponent<{
messages: ChatMessageVO[]
currentUserId: string
roomName?: string
meetingUrl?: string
showMeeting?: boolean
fileDownloadUrl?: string
}, {}, {}, {}, {}, {}, {}, {
header?: () => any
'action-area'?: () => any
}>
export default ChatRoom
}
// ========== API 模块 ==========
declare module 'shared/api' {
export const api: any
import type { AxiosResponse, AxiosRequestConfig } from 'axios'
interface ApiInstance {
get<T = any>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>
post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>
put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>
delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>
uploadPut<T = any>(url: string, data: FormData, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>
}
export const api: ApiInstance
export const TokenManager: any
export const authAPI: any
export const fileAPI: any
export const workcaseAPI: any
}
declare module 'shared/api/auth' {
@@ -96,18 +79,9 @@ declare module 'shared/api/ai' {
export const aiChatAPI: any
}
declare module 'shared/api/workcase' {
export const workcaseAPI: any
export const workcaseChatAPI: any
}
// ============ types模块 ==================
declare module 'shared/types' {
import type { BaseDTO } from '../../../shared/src/types/base'
// 重新导出 base
export type { BaseDTO }
export type { BaseDTO, BaseVO } from '../../../shared/src/types/base'
// 重新导出 response
export type { ResultDomain } from '../../../shared/src/types/response'
@@ -138,39 +112,6 @@ declare module 'shared/types' {
CommentMessageParams
} from '../../../shared/src/types/ai'
// 重新导出 workcase
export type {
TbWorkcaseDTO,
TbWorkcaseProcessDTO,
TbWorkcaseDeviceDTO,
// 聊天室相关
TbChatRoomDTO,
TbChatRoomMessageDTO,
TbChatRoomMemberDTO,
TbVideoMeetingDTO,
TbMeetingParticipantDTO,
TbMeetingTranscriptionDTO,
ChatRoomVO,
ChatMessageVO,
ChatRoomMessageVO,
ChatMemberVO,
VideoMeetingVO,
MeetingParticipantVO,
SendMessageParam,
CreateMeetingParam,
MarkReadParam,
// 客服相关
TbCustomerServiceDTO,
CustomerServiceVO,
// 词云
TbWordCloudDTO,
// 来客相关
TbGuestDTO,
GuestVO,
CustomerVO,
ConversationVO
} from '../../../shared/src/types/workcase'
// 重新导出 menu
export type { MenuItem, toMenuItem, toMenuItems } from '../../../shared/src/types/menu'
}

View File

@@ -1,6 +1,6 @@
import { api } from '@/api/index'
import type { ResultDomain } from '@/types'
import type { TbChat, TbChatMessage, ChatPrepareData, StopChatParams, CommentMessageParams, DifyFileInfo } from '@/types/ai'
import type { TbChat, TbChatMessage, ChatPrepareData, StopChatParam, CommentMessageParam, DifyFileInfo } from '@/types/ai'
/**
* @description AI对话相关接口
@@ -93,7 +93,7 @@ export const aiChatAPI = {
* 停止对话
* @param params 停止参数
*/
async stopChat(params: StopChatParams): Promise<ResultDomain<boolean>> {
async stopChat(params: StopChatParam): Promise<ResultDomain<boolean>> {
const response = await api.post<boolean>(`${this.baseUrl}/stop`, params)
return response.data
},
@@ -102,7 +102,7 @@ export const aiChatAPI = {
* 评价消息
* @param params 评价参数
*/
async commentMessage(params: CommentMessageParams): Promise<ResultDomain<boolean>> {
async commentMessage(params: CommentMessageParam): Promise<ResultDomain<boolean>> {
const response = await api.post<boolean>(`${this.baseUrl}/comment`, params)
return response.data
},

View File

@@ -2,6 +2,5 @@ export * from './base'
export * from './dynamicFormItem'
export * from './ai'
export * from './file'
export * from './chatRoom'
// 通用视图组件
export { default as IframeView } from './iframe/IframeView.vue'

View File

@@ -90,22 +90,120 @@ export interface ChatPrepareData {
userType?: boolean
}
// ==================== 请求参数类型(必传校验) ====================
/**
* 创建对话参数
*/
export interface CreateChatParam {
/** 智能体ID必传 */
agentId: string
/** 用户ID必传 */
userId: string
/** 用户类型(必传) */
userType: boolean
/** 对话标题 */
title?: string
}
/**
* 准备流式对话参数
*/
export interface PrepareChatParam {
/** 对话ID必传 */
chatId: string
/** 用户问题(必传) */
query: string
/** 智能体ID必传 */
agentId: string
/** 用户类型(必传) */
userType: boolean
/** 用户ID */
userId?: string
/** 文件列表 */
files?: DifyFileInfo[]
}
/**
* 停止对话参数
*/
export interface StopChatParams {
export interface StopChatParam {
/** 任务ID必传 */
taskId: string
/** 智能体ID必传 */
agentId: string
/** 用户ID必传 */
userId: string
}
/**
* 评价消息参数
*/
export interface CommentMessageParams {
export interface CommentMessageParam {
/** 智能体ID必传 */
agentId: string
/** 对话ID必传 */
chatId: string
/** 消息ID必传 */
messageId: string
/** 评价内容(必传) */
comment: string
/** 用户ID必传 */
userId: string
}
/**
* 查询对话列表参数
*/
export interface ChatListParam {
/** 用户ID必传 */
userId: string
/** 智能体ID */
agentId?: string
}
/**
* 查询对话消息列表参数
*/
export interface ChatMessageListParam {
/** 对话ID必传 */
chatId: string
}
// ==================== SSE 流式对话类型 ====================
/**
* SSE 消息事件数据
*/
export interface SSEMessageData {
/** 事件类型 */
event?: string
/** 回答内容 */
answer?: string
/** 任务ID */
task_id?: string
/** 错误消息 */
message?: string
}
/**
* SSE 回调函数
*/
export interface SSECallbacks {
/** 收到消息 */
onMessage?: (data: SSEMessageData) => void
/** 消息结束 */
onEnd?: (taskId: string) => void
/** 发生错误 */
onError?: (error: string) => void
/** 请求完成(无论成功失败) */
onComplete?: () => void
}
/**
* SSE 请求任务对象
*/
export interface SSETask {
/** 停止请求 */
abort: () => void
}

View File

@@ -12,4 +12,4 @@ export * from "./message"
export * from "./ai"
export * from "./crontab"
export * from "./bidding"
export * from "./workcase"
// workcase 类型已移至各自的服务包中(如 workcase_wechat

View File

@@ -40,13 +40,11 @@ export default defineConfig({
'./components/iframe/IframeView.vue': './src/components/iframe/IframeView.vue',
'./components/ai/knowledge/DocumentSegment.vue': './src/components/ai/knowledge/documentSegment/DocumentSegment.vue',
'./components/ai/knowledge/DocumentDetail.vue': './src/components/ai/knowledge/documentDetail/DocumentDetail.vue',
'./components/chatRoom/ChatRoom.vue': './src/components/chatRoom/chatRoom/ChatRoom.vue',
// ========== API 模块 ==========
'./api': './src/api/index.ts',
'./api/auth': './src/api/auth/auth.ts',
'./api/file': './src/api/file/file.ts',
'./api/workcase': './src/api/workcase/index.ts',
'./api/ai': './src/api/ai/index.ts',
// ========== Utils 工具模块 ==========
@@ -62,7 +60,6 @@ export default defineConfig({
'./types/auth': './src/types/auth/index.ts',
'./types/file': './src/types/file/index.ts',
'./types/sys': './src/types/sys/index.ts',
'./types/workcase': './src/types/workcase/index.ts',
'./types/ai': './src/types/ai/index.ts',
// ========== Config 配置模块 ==========

View File

@@ -1,5 +1,5 @@
import { api } from '@/api/index'
import type { ResultDomain, PageRequest } from '@/types'
import { api } from 'shared/api'
import type { ResultDomain, PageRequest } from 'shared/types'
import type { TbWorkcaseDTO, TbWorkcaseProcessDTO, TbWorkcaseDeviceDTO } from '@/types/workcase'
/**

View File

@@ -1,7 +1,5 @@
import { api } from '@/api/index'
import type { ResultDomain, PageRequest } from '@/types'
import type { TbChat, TbChatMessage, ChatPrepareData } from '@/types/ai'
import type { TbWorkcaseDTO } from '@/types/workcase/workcase'
import { api } from 'shared/api'
import type { ResultDomain, PageRequest } from 'shared/types'
import type {
TbChatRoomDTO,
TbChatRoomMemberDTO,
@@ -12,10 +10,10 @@ import type {
ChatMemberVO,
ChatRoomMessageVO,
CustomerServiceVO
} from '@/types/workcase/chatRoom'
} from '@/types/workcase'
/**
* @description
* @description ChatRoom
* @filename workcaseChat.ts
* @author cascade
* @copyright xyzh
@@ -24,91 +22,6 @@ import type {
export const workcaseChatAPI = {
baseUrl: '/urban-lifeline/workcase/chat',
// ====================== AI对话管理 ======================
/**
*
*/
async createChat(chat: TbChat): Promise<ResultDomain<TbChat>> {
const response = await api.post<TbChat>(`${this.baseUrl}`, chat)
return response.data
},
/**
*
*/
async updateChat(chat: TbChat): Promise<ResultDomain<TbChat>> {
const response = await api.put<TbChat>(`${this.baseUrl}`, chat)
return response.data
},
/**
*
*/
async getChatList(filter: TbChat): Promise<ResultDomain<TbChat>> {
const response = await api.post<TbChat>(`${this.baseUrl}/list`, filter)
return response.data
},
/**
*
*/
async getChatMessageList(filter: TbChat): Promise<ResultDomain<TbChatMessage>> {
const response = await api.post<TbChatMessage>(`${this.baseUrl}/message/list`, filter)
return response.data
},
/**
*
*/
async prepareChatMessageSession(prepareData: ChatPrepareData): Promise<ResultDomain<string>> {
const response = await api.post<string>(`${this.baseUrl}/prepare`, prepareData)
return response.data
},
/**
* SSE- EventSource URL
*/
getStreamUrl(sessionId: string): string {
return `${this.baseUrl}/stream/${sessionId}`
},
/**
*
*/
async stopChat(filter: TbChat, taskId: string): Promise<ResultDomain<boolean>> {
const response = await api.post<boolean>(`${this.baseUrl}/stop/${taskId}`, filter)
return response.data
},
/**
*
*/
async commentChatMessage(filter: TbChat, messageId: string, comment: string): Promise<ResultDomain<boolean>> {
const response = await api.post<boolean>(`${this.baseUrl}/comment`, filter, {
params: { messageId, comment }
})
return response.data
},
// ====================== 对话分析 ======================
/**
* AI预填工单信息
*/
async analyzeChat(chatId: string): Promise<ResultDomain<TbWorkcaseDTO>> {
const response = await api.get<TbWorkcaseDTO>(`${this.baseUrl}/analyze/${chatId}`)
return response.data
},
/**
*
*/
async summaryChat(chatId: string): Promise<ResultDomain<TbWorkcaseDTO>> {
const response = await api.post<TbWorkcaseDTO>(`${this.baseUrl}/summary/${chatId}`)
return response.data
},
// ====================== ChatRoom聊天室管理 ======================
/**

View File

@@ -116,20 +116,11 @@
<script setup lang="ts">
import { ref, nextTick } from 'vue'
import { FileText, Video, Paperclip, Send } from 'lucide-vue-next'
import IframeView from '@/components/iframe/IframeView.vue'
interface ChatMessageVO {
messageId: string
senderId: string
senderName: string
senderAvatar: string
content: string
files: string[]
sendTime: string
}
import IframeView from 'shared/components/iframe/IframeView.vue'
import type { ChatRoomMessageVO } from '@/types/workcase'
interface Props {
messages: ChatMessageVO[]
messages: ChatRoomMessageVO[]
currentUserId: string
roomName?: string
meetingUrl?: string
@@ -218,7 +209,8 @@ const handleKeyDown = (e: KeyboardEvent) => {
}
//
const formatTime = (time: string) => {
const formatTime = (time?: string) => {
if (!time) return ''
const date = new Date(time)
const now = new Date()
const diff = now.getTime() - date.getTime()

View File

@@ -0,0 +1 @@
export * from './chatRoom'

View File

@@ -46,40 +46,23 @@ declare module 'shared/components/ai/knowledge/DocumentDetail.vue' {
export default DocumentDetail
}
declare module 'shared/components/chatRoom/ChatRoom.vue' {
import { DefineComponent } from 'vue'
interface ChatMessageVO {
messageId: string
senderId: string
senderName: string
senderAvatar: string
content: string
files: string[]
sendTime: string
}
const ChatRoom: DefineComponent<{
messages: ChatMessageVO[]
currentUserId: string
roomName?: string
meetingUrl?: string
showMeeting?: boolean
fileDownloadUrl?: string
}, {}, {}, {}, {}, {}, {}, {
header?: () => any
'action-area'?: () => any
}>
export default ChatRoom
}
// ========== API 模块 ==========
declare module 'shared/api' {
export const api: any
import type { AxiosResponse, AxiosRequestConfig } from 'axios'
interface ApiInstance {
get<T = any>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>
post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>
put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>
delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>
uploadPut<T = any>(url: string, data: FormData, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>
}
export const api: ApiInstance
export const TokenManager: any
export const authAPI: any
export const fileAPI: any
export const workcaseAPI: any
}
declare module 'shared/api/auth' {
@@ -96,18 +79,9 @@ declare module 'shared/api/ai' {
export const aiChatAPI: any
}
declare module 'shared/api/workcase' {
export const workcaseAPI: any
export const workcaseChatAPI: any
}
// ============ types模块 ==================
declare module 'shared/types' {
import type { BaseDTO } from '../../../shared/src/types/base'
// 重新导出 base
export type { BaseDTO }
export type { BaseDTO, BaseVO } from '../../../shared/src/types/base'
// 重新导出 response
export type { ResultDomain } from '../../../shared/src/types/response'
@@ -138,39 +112,6 @@ declare module 'shared/types' {
CommentMessageParams
} from '../../../shared/src/types/ai'
// 重新导出 workcase
export type {
TbWorkcaseDTO,
TbWorkcaseProcessDTO,
TbWorkcaseDeviceDTO,
// 聊天室相关
TbChatRoomDTO,
TbChatRoomMessageDTO,
TbChatRoomMemberDTO,
TbVideoMeetingDTO,
TbMeetingParticipantDTO,
TbMeetingTranscriptionDTO,
ChatRoomVO,
ChatMessageVO,
ChatRoomMessageVO,
ChatMemberVO,
VideoMeetingVO,
MeetingParticipantVO,
SendMessageParam,
CreateMeetingParam,
MarkReadParam,
// 客服相关
TbCustomerServiceDTO,
CustomerServiceVO,
// 词云
TbWordCloudDTO,
// 来客相关
TbGuestDTO,
GuestVO,
CustomerVO,
ConversationVO
} from '../../../shared/src/types/workcase'
// 重新导出 menu
export type { MenuItem, toMenuItem, toMenuItems } from '../../../shared/src/types/menu'
}

View File

@@ -1,5 +1,4 @@
import { BaseVO } from '../base'
import { BaseDTO } from '../base'
import type { BaseVO, BaseDTO } from 'shared/types'
// ==================== DTO ====================
@@ -292,60 +291,3 @@ export interface MarkReadParam {
roomId: string
messageIds?: string[]
}
// ==================== 客服相关 ====================
/**
* DTO
*/
export interface TbCustomerServiceDTO extends BaseDTO {
userId?: string
userName?: string
status?: string
maxConcurrentChats?: number
currentChatCount?: number
totalServedCount?: number
avgResponseTime?: number
avgRating?: number
skills?: string[]
priority?: number
lastOnlineTime?: string
}
/**
* VO
*/
export interface CustomerServiceVO extends BaseVO {
userId?: string
userName?: string
userAvatar?: string
status?: string
statusName?: string
maxConcurrentChats?: number
currentChatCount?: number
totalServedCount?: number
avgResponseTime?: number
avgResponseTimeFormatted?: string
avgRating?: number
skills?: string[]
skillNames?: string[]
priority?: number
lastOnlineTime?: string
isAvailable?: boolean
}
// ==================== 词云相关 ====================
/**
* DTO
*/
export interface TbWordCloudDTO extends BaseDTO {
wordCloudId?: string
word?: string
category?: string
weight?: number
frequency?: number
sentiment?: string
source?: string
relatedWords?: string[]
}

View File

@@ -1,4 +1,4 @@
import { BaseVO } from '../base'
import type { BaseVO } from 'shared/types'
// ==================== VO ====================

View File

@@ -1,4 +1,4 @@
import { BaseDTO, BaseVO } from '../base'
import type { BaseDTO, BaseVO } from 'shared/types'
// ==================== DTO ====================

View File

@@ -1,4 +1,4 @@
import { BaseDTO } from '../base'
import type { BaseDTO } from 'shared/types'
// ==================== DTO ====================

View File

@@ -1,4 +1,4 @@
import type { BaseDTO } from '@/types/base'
import type { BaseDTO } from 'shared/types'
/**
*

View File

@@ -27,7 +27,7 @@
:key="room.roomId"
class="room-item"
:class="{ active: currentRoomId === room.roomId }"
@click="selectRoom(room.roomId)"
@click="selectRoom(room.roomId!)"
>
<!-- 头像 -->
<div class="room-avatar">
@@ -44,8 +44,8 @@
</div>
<!-- 未读红点 -->
<div v-if="room.unreadCount > 0" class="unread-badge">
{{ room.unreadCount > 99 ? '99+' : room.unreadCount }}
<div v-if="(room.unreadCount ?? 0) > 0" class="unread-badge">
{{ (room.unreadCount ?? 0) > 99 ? '99+' : room.unreadCount }}
</div>
</div>
</div>
@@ -117,12 +117,12 @@
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
import { ElButton, ElInput, ElDialog, ElMessage } from 'element-plus'
import { Search, FileText, MessageSquare } from 'lucide-vue-next'
import ChatRoom from 'shared/components/chatRoom/ChatRoom.vue'
import { ChatRoom } from '@/components/chatRoom'
import WorkcaseDetail from '@/views/public/workcase/WorkcaseDetail/WorkcaseDetail.vue'
import { workcaseChatAPI } from 'shared/api/workcase'
import { workcaseChatAPI } from '@/api/workcase'
import { fileAPI } from 'shared/api/file'
import { FILE_DOWNLOAD_URL } from '@/config'
import type { ChatRoomVO, ChatRoomMessageVO, TbChatRoomMessageDTO } from 'shared/types'
import type { ChatRoomVO, ChatRoomMessageVO, TbChatRoomMessageDTO } from '@/types/workcase'
import SockJS from 'sockjs-client'
import { Client } from '@stomp/stompjs'