351 lines
11 KiB
Plaintext
351 lines
11 KiB
Plaintext
/**
|
||
* 统一的自定义操作服务
|
||
* 管理所有自定义元素的交互事件:打开预览、远程桌面、刷新文件树、打开页面等
|
||
*
|
||
* 设计参考 PC端: src/models/conversationInfo.ts
|
||
* - openPreviewView: 打开预览视图,设置viewMode为'preview',显示文件树,刷新文件列表
|
||
* - openDesktopView: 打开远程桌面视图,设置viewMode为'desktop',启动容器,启动保活
|
||
* - handleRefreshFileList: 刷新文件列表,调用apiGetStaticFileList
|
||
*
|
||
* 详细接入文档请参考: integration_guide.md
|
||
*/
|
||
|
||
import { API_BASE_URL } from '@/constants/config'
|
||
|
||
/**
|
||
* 事件类型枚举(对应PC端 EVENT_TYPE)
|
||
*/
|
||
export enum CustomEventType {
|
||
/** 刷新文件列表 */
|
||
REFRESH_FILE_LIST = 'custom_action_refresh_file_list',
|
||
/** 打开预览视图 */
|
||
OPEN_PREVIEW = 'custom_action_open_preview',
|
||
/** 打开远程桌面 */
|
||
OPEN_DESKTOP = 'custom_action_open_desktop',
|
||
/** 打开扩展页面 */
|
||
OPEN_PAGE = 'custom_action_open_page',
|
||
/** 打开外部链接 */
|
||
OPEN_LINK = 'custom_action_open_link',
|
||
}
|
||
|
||
/**
|
||
* 视图模式枚举(对应PC端 viewMode)
|
||
*/
|
||
export enum ViewModeEnum {
|
||
/** 预览模式 */
|
||
PREVIEW = 'preview',
|
||
/** 远程桌面模式 */
|
||
DESKTOP = 'desktop',
|
||
}
|
||
|
||
/**
|
||
* 操作类型枚举
|
||
*/
|
||
export enum CustomActionType {
|
||
/** 打开预览视图(文件预览模式) */
|
||
OPEN_PREVIEW = 'OPEN_PREVIEW',
|
||
/** 打开远程桌面视图 */
|
||
OPEN_DESKTOP = 'OPEN_DESKTOP',
|
||
/** 刷新文件树 */
|
||
REFRESH_FILE_LIST = 'REFRESH_FILE_LIST',
|
||
/** 打开扩展页面(iframe/webview) */
|
||
OPEN_PAGE = 'OPEN_PAGE',
|
||
/** 打开外部链接 */
|
||
OPEN_LINK = 'OPEN_LINK',
|
||
}
|
||
|
||
/**
|
||
* 操作参数接口
|
||
*/
|
||
export interface CustomActionParams {
|
||
type: CustomActionType
|
||
conversationId?: string
|
||
uri?: string
|
||
params?: Record<string, any>
|
||
method?: string
|
||
dataType?: string
|
||
requestId?: string
|
||
}
|
||
|
||
/**
|
||
* 页面预览选项
|
||
*/
|
||
export interface OpenPageOptions {
|
||
uri: string
|
||
params?: Record<string, any>
|
||
method?: string
|
||
dataType?: string
|
||
requestId?: string
|
||
}
|
||
|
||
/**
|
||
* 打开预览事件数据(对应PC端 openPreviewView 逻辑)
|
||
*/
|
||
export interface OpenPreviewEventData {
|
||
conversationId: string
|
||
viewMode: ViewModeEnum
|
||
}
|
||
|
||
/**
|
||
* 打开远程桌面事件数据(对应PC端 openDesktopView 逻辑)
|
||
*/
|
||
export interface OpenDesktopEventData {
|
||
conversationId: string
|
||
viewMode: ViewModeEnum
|
||
}
|
||
|
||
/**
|
||
* 刷新文件列表事件数据(对应PC端 handleRefreshFileList 逻辑)
|
||
*/
|
||
export interface RefreshFileListEventData {
|
||
conversationId: string
|
||
}
|
||
|
||
/**
|
||
* 打开页面事件数据
|
||
*/
|
||
export interface OpenPageEventData {
|
||
uri: string
|
||
method: string
|
||
dataType: string
|
||
requestId: string
|
||
}
|
||
|
||
/**
|
||
* 统一的自定义操作服务类
|
||
*
|
||
* 使用示例:
|
||
* - CustomActionService.openPreviewView(conversationId) // 打开预览视图
|
||
* - CustomActionService.openDesktopView(conversationId) // 打开远程桌面
|
||
* - CustomActionService.refreshFileList(conversationId) // 刷新文件树
|
||
* - CustomActionService.openPage({ uri: '/page/index', params: { id: 1 } }) // 打开扩展页面
|
||
* - CustomActionService.openLink('https://example.com') // 打开外部链接
|
||
*
|
||
* 事件监听示例:
|
||
* uni.$on(CustomEventType.OPEN_PREVIEW, (data: OpenPreviewEventData) => { ... })
|
||
* uni.$on(CustomEventType.REFRESH_FILE_LIST, (data: RefreshFileListEventData) => { ... })
|
||
*/
|
||
export class CustomActionService {
|
||
/**
|
||
* 打开预览视图
|
||
* 对应PC端 openPreviewView 方法
|
||
* 切换到文件预览模式并刷新文件列表
|
||
* @param conversationId 会话ID
|
||
*/
|
||
static openPreviewView(conversationId: string): void {
|
||
if (!conversationId) {
|
||
console.warn('[CustomActionService] openPreviewView: conversationId is required')
|
||
return
|
||
}
|
||
|
||
// 移除 chat- 前缀
|
||
const idStr = String(conversationId)
|
||
const cid = idStr.startsWith('chat-') ? idStr.replace('chat-', '') : idStr
|
||
|
||
// console.log('[CustomActionService] openPreviewView:', cid)
|
||
|
||
// 发送打开预览视图事件(对应PC端 setViewMode('preview') + setIsFileTreeVisible(true))
|
||
const eventData: OpenPreviewEventData = {
|
||
conversationId: cid,
|
||
viewMode: ViewModeEnum.PREVIEW
|
||
}
|
||
// console.log('[CustomActionService] Action: OPEN_PREVIEW, Params:', { conversationId })
|
||
uni.$emit(CustomEventType.OPEN_PREVIEW, eventData)
|
||
|
||
// 触发文件列表刷新(对应PC端 eventBus.emit(EVENT_TYPE.RefreshFileList, cId))
|
||
this.refreshFileList(conversationId)
|
||
}
|
||
|
||
/**
|
||
* 打开远程桌面视图
|
||
* 对应PC端 openDesktopView 方法
|
||
* 切换到远程桌面模式并启动VNC连接
|
||
* @param conversationId 会话ID
|
||
*/
|
||
static openDesktopView(conversationId: string): void {
|
||
if (!conversationId) {
|
||
console.warn('[CustomActionService] openDesktopView: conversationId is required')
|
||
return
|
||
}
|
||
|
||
// 移除 chat- 前缀
|
||
const idStr = String(conversationId)
|
||
const cid = idStr.startsWith('chat-') ? idStr.replace('chat-', '') : idStr
|
||
|
||
// console.log('[CustomActionService] openDesktopView:', cid)
|
||
|
||
// 发送打开远程桌面事件(对应PC端 setViewMode('desktop') + setIsFileTreeVisible(true) + apiEnsurePod)
|
||
const eventData: OpenDesktopEventData = {
|
||
conversationId: cid,
|
||
viewMode: ViewModeEnum.DESKTOP
|
||
}
|
||
// console.log('[CustomActionService] Action: OPEN_DESKTOP, Params:', { conversationId })
|
||
uni.$emit(CustomEventType.OPEN_DESKTOP, eventData)
|
||
}
|
||
|
||
/**
|
||
* 刷新文件树
|
||
* 对应PC端 handleRefreshFileList 方法
|
||
* 重新获取会话相关的文件列表
|
||
* @param conversationId 会话ID
|
||
*/
|
||
static refreshFileList(conversationId: string): void {
|
||
if (!conversationId) {
|
||
console.warn('[CustomActionService] refreshFileList: conversationId is required')
|
||
return
|
||
}
|
||
|
||
// 移除 chat- 前缀
|
||
const idStr = String(conversationId)
|
||
const cid = idStr.startsWith('chat-') ? idStr.replace('chat-', '') : idStr
|
||
|
||
// console.log('[CustomActionService] refreshFileList:', cid)
|
||
|
||
// 发送刷新文件列表事件(对应PC端 runGetStaticFileList(targetId))
|
||
const eventData: RefreshFileListEventData = {
|
||
conversationId: cid
|
||
}
|
||
// console.log('[CustomActionService] Emitting REFRESH_FILE_LIST event:', eventData)
|
||
// uni.$emit(CustomEventType.REFRESH_FILE_LIST, eventData)
|
||
uni.$emit('refreshFileList', cid)
|
||
}
|
||
|
||
/**
|
||
* 打开扩展页面
|
||
* 在iframe或webview中打开指定页面
|
||
* @param options 页面选项
|
||
*/
|
||
static openPage(options: OpenPageOptions): void {
|
||
if (!options.uri) {
|
||
console.warn('[CustomActionService] openPage: uri is required')
|
||
return
|
||
}
|
||
|
||
// console.log('[CustomActionService] openPage:', options)
|
||
|
||
// 构建完整的URL
|
||
let fullUri = options.uri
|
||
if (options.params && Object.keys(options.params).length > 0) {
|
||
const queryString = Object.entries(options.params)
|
||
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
|
||
.join('&')
|
||
fullUri = `${fullUri}${fullUri.includes('?') ? '&' : '?'}${queryString}`
|
||
}
|
||
|
||
// 发送打开页面事件
|
||
const eventData: OpenPageEventData = {
|
||
uri: fullUri,
|
||
method: options.method || 'browser_open_page',
|
||
dataType: options.dataType || 'html',
|
||
requestId: options.requestId || ''
|
||
}
|
||
// console.log('[CustomActionService] Action: OPEN_PAGE, Params:', { uri: fullUri, method: eventData.method })
|
||
uni.$emit(CustomEventType.OPEN_PAGE, eventData)
|
||
}
|
||
|
||
/**
|
||
* 打开外部链接
|
||
* 在新窗口或跳转页面打开链接
|
||
* @param uri 链接地址
|
||
* @param params 查询参数
|
||
*/
|
||
static openLink(uri: string, params?: Record<string, any>): void {
|
||
if (!uri) {
|
||
console.warn('[CustomActionService] openLink: uri is required')
|
||
return
|
||
}
|
||
|
||
// console.log('[CustomActionService] openLink:', uri, params)
|
||
|
||
// 构建完整的URL
|
||
let fullUri = uri
|
||
if (params && Object.keys(params).length > 0) {
|
||
const queryString = Object.entries(params)
|
||
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
|
||
.join('&')
|
||
fullUri = `${fullUri}${fullUri.includes('?') ? '&' : '?'}${queryString}`
|
||
}
|
||
|
||
// #ifdef H5 || WEB
|
||
window.open(fullUri, '_blank')
|
||
// #endif
|
||
|
||
// #ifdef MP-WEIXIN
|
||
// 小程序环境下使用webview打开
|
||
uni.navigateTo({
|
||
url: `/subpackages/pages/common/webview/webview?url=${encodeURIComponent(fullUri)}`
|
||
})
|
||
// #endif
|
||
|
||
// 同时发送事件,允许页面自定义处理
|
||
// console.log('[CustomActionService] Action: OPEN_LINK, Params:', { uri: fullUri })
|
||
uni.$emit(CustomEventType.OPEN_LINK, { uri: fullUri })
|
||
}
|
||
|
||
/**
|
||
* 统一的动作分发器
|
||
* 根据动作类型调用相应的处理方法
|
||
* @param action 动作参数
|
||
*/
|
||
static dispatch(action: CustomActionParams): void {
|
||
if (!action || !action.type) {
|
||
console.warn('[CustomActionService] dispatch: action type is required')
|
||
return
|
||
}
|
||
|
||
// console.log('[CustomActionService] dispatch:', action.type, action)
|
||
|
||
switch (action.type) {
|
||
case CustomActionType.OPEN_PREVIEW:
|
||
if (action.conversationId) {
|
||
this.openPreviewView(action.conversationId)
|
||
}
|
||
break
|
||
|
||
case CustomActionType.OPEN_DESKTOP:
|
||
if (action.conversationId) {
|
||
this.openDesktopView(action.conversationId)
|
||
}
|
||
break
|
||
|
||
case CustomActionType.REFRESH_FILE_LIST:
|
||
if (action.conversationId) {
|
||
this.refreshFileList(action.conversationId)
|
||
}
|
||
break
|
||
|
||
case CustomActionType.OPEN_PAGE:
|
||
if (action.uri) {
|
||
this.openPage({
|
||
uri: action.uri,
|
||
params: action.params,
|
||
method: action.method,
|
||
dataType: action.dataType,
|
||
requestId: action.requestId
|
||
})
|
||
}
|
||
break
|
||
|
||
case CustomActionType.OPEN_LINK:
|
||
if (action.uri) {
|
||
this.openLink(action.uri, action.params)
|
||
}
|
||
break
|
||
|
||
default:
|
||
console.warn('[CustomActionService] dispatch: unknown action type:', action.type)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 导出事件类型,方便外部监听
|
||
export { CustomEventType as EVENT_TYPE }
|
||
|
||
// 导出默认实例方法,方便使用
|
||
export const openPreviewView = CustomActionService.openPreviewView.bind(CustomActionService)
|
||
export const openDesktopView = CustomActionService.openDesktopView.bind(CustomActionService)
|
||
export const refreshFileList = CustomActionService.refreshFileList.bind(CustomActionService)
|
||
export const openPage = CustomActionService.openPage.bind(CustomActionService)
|
||
export const openLink = CustomActionService.openLink.bind(CustomActionService)
|
||
export const dispatchAction = CustomActionService.dispatch.bind(CustomActionService)
|