From 9c4f73ac9cc52e801614692a71c2c439630f6046 Mon Sep 17 00:00:00 2001 From: wangys <3401275564@qq.com> Date: Fri, 19 Dec 2025 17:34:30 +0800 Subject: [PATCH] =?UTF-8?q?web=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../packages/bidding/src/types/shared.d.ts | 116 +++-- .../packages/platform/src/types/shared.d.ts | 117 +++-- .../packages/shared/src/api/ai/agent.ts | 68 +++ .../packages/shared/src/api/ai/aiKnowledge.ts | 262 +++++++++++ .../packages/shared/src/api/ai/aichat.ts | 124 +++++ .../packages/shared/src/api/ai/index.ts | 3 + .../packages/shared/src/api/index.ts | 17 +- .../packages/shared/src/api/workcase/index.ts | 1 + .../shared/src/api/workcase/workcase.ts | 185 ++++++++ .../src/components/fileupload/FileUpload.vue | 65 ++- .../packages/shared/src/types/agent/agent.ts | 139 ------ .../packages/shared/src/types/agent/index.ts | 1 - .../packages/shared/src/types/ai/agent.ts | 35 ++ .../packages/shared/src/types/ai/aiChat.ts | 111 +++++ .../shared/src/types/ai/aiKnowledge.ts | 73 +++ .../packages/shared/src/types/ai/index.ts | 3 + .../packages/shared/src/types/index.ts | 2 +- .../shared/src/types/workcase/workcase.ts | 330 +++----------- .../packages/shared/vite.config.ts | 4 + .../packages/workcase/src/types/shared.d.ts | 111 +++-- .../views/admin/knowledge/KnowLedgeView.vue | 428 +++++++++++------- .../src/views/admin/workcase/WorkcaseView.vue | 287 +++++++++--- 22 files changed, 1660 insertions(+), 822 deletions(-) create mode 100644 urbanLifelineWeb/packages/shared/src/api/ai/agent.ts create mode 100644 urbanLifelineWeb/packages/shared/src/api/ai/aiKnowledge.ts create mode 100644 urbanLifelineWeb/packages/shared/src/api/ai/aichat.ts create mode 100644 urbanLifelineWeb/packages/shared/src/api/ai/index.ts create mode 100644 urbanLifelineWeb/packages/shared/src/api/workcase/index.ts create mode 100644 urbanLifelineWeb/packages/shared/src/api/workcase/workcase.ts delete mode 100644 urbanLifelineWeb/packages/shared/src/types/agent/agent.ts delete mode 100644 urbanLifelineWeb/packages/shared/src/types/agent/index.ts create mode 100644 urbanLifelineWeb/packages/shared/src/types/ai/agent.ts create mode 100644 urbanLifelineWeb/packages/shared/src/types/ai/aiChat.ts create mode 100644 urbanLifelineWeb/packages/shared/src/types/ai/aiKnowledge.ts create mode 100644 urbanLifelineWeb/packages/shared/src/types/ai/index.ts diff --git a/urbanLifelineWeb/packages/bidding/src/types/shared.d.ts b/urbanLifelineWeb/packages/bidding/src/types/shared.d.ts index 7cc0755f..379edaf5 100644 --- a/urbanLifelineWeb/packages/bidding/src/types/shared.d.ts +++ b/urbanLifelineWeb/packages/bidding/src/types/shared.d.ts @@ -28,16 +28,13 @@ declare module 'shared/components/iframe/IframeView.vue' { export default IframeView } -declare module 'shared/components/iframe/IframeView.vue' { - import { DefineComponent } from 'vue' - const IframeView: DefineComponent<{}, {}, any> - export default IframeView -} - // ========== API 模块 ========== declare module 'shared/api' { export const api: any export const TokenManager: any + export const authAPI: any + export const fileAPI: any + export const workcaseAPI: any } declare module 'shared/api/auth' { @@ -48,26 +45,64 @@ declare module 'shared/api/file' { export const fileAPI: any } -declare module 'shared/api' { - export const authAPI: any - export const fileAPI: any - export const TokenManager: any - export const api: any +declare module 'shared/api/ai' { + export const agentAPI: any + export const aiKnowledgeAPI: any + export const aiChatAPI: any } -// 保留旧的导出路径(向后兼容) -declare module 'shared/FileUpload' { - import { DefineComponent } from 'vue' - const FileUpload: DefineComponent<{}, {}, any> - export default FileUpload +declare module 'shared/api/workcase' { + export const workcaseAPI: any } -declare module 'shared/DynamicFormItem' { - import { DefineComponent } from 'vue' - const DynamicFormItem: DefineComponent<{}, {}, any> - export default DynamicFormItem +// ============ types模块 ================== +declare module 'shared/types' { + import type { BaseDTO } from '../../../shared/src/types/base' + + // 重新导出 base + export type { BaseDTO } + + // 重新导出 response + export type { ResultDomain } from '../../../shared/src/types/response' + + // 重新导出 page + export type { PageDomain, PageParam, PageRequest } from '../../../shared/src/types/page' + + // 重新导出 auth + export type { LoginParam, LoginDomain } from '../../../shared/src/types/auth' + + // 重新导出 sys + export type { SysUserVO, SysConfigVO, TbSysViewDTO } from '../../../shared/src/types/sys' + + // 重新导出 file + export type { TbSysFileDTO } from '../../../shared/src/types/file' + + // 重新导出 ai + export type { + TbKnowledge, + TbKnowledgeFile, + TbAgent, + PromptCard, + TbChat, + TbChatMessage, + DifyFileInfo, + ChatPrepareData, + StopChatParams, + CommentMessageParams + } from '../../../shared/src/types/ai' + + // 重新导出 workcase + export type { + TbWorkcaseDTO, + TbWorkcaseProcessDTO, + TbWorkcaseDeviceDTO + } from '../../../shared/src/types/workcase' + + // 重新导出 menu + export type { MenuItem, toMenuItem, toMenuItems } from '../../../shared/src/types/menu' } +// ================ utils工具 ========================== declare module 'shared/utils' { export const initAesEncrypt: any export const getAesInstance: any @@ -78,47 +113,6 @@ declare module 'shared/utils' { export const getFilePreviewUrl: any } -declare module 'shared/types' { - import { RouteRecordRaw } from 'vue-router' - - export type LoginParam = any - export type LoginDomain = any - export type SysUserVO = any - export type TbSysFileDTO = any - export type SysConfigVO = any - export type ResultDomain = any - - // 视图类型(用于路由和菜单) - export interface TbSysViewDTO { - viewId?: string - name?: string - parentId?: string - url?: string - component?: string - iframeUrl?: string - icon?: string - type?: number - viewType?: string - service?: string - layout?: string - orderNum?: number - description?: string - children?: TbSysViewDTO[] - } - - // 菜单项类型(扩展 TbSysViewDTO) - export interface MenuItem extends TbSysViewDTO { - key: string - label: string - expanded?: boolean - children?: MenuItem[] - } - - // 菜单工具函数 - export function toMenuItem(view: TbSysViewDTO, expanded?: boolean): MenuItem - export function toMenuItems(views: TbSysViewDTO[], defaultExpanded?: boolean): MenuItem[] -} - declare module 'shared/utils/route' { import { RouteRecordRaw } from 'vue-router' import type { TbSysViewDTO } from 'shared/types' diff --git a/urbanLifelineWeb/packages/platform/src/types/shared.d.ts b/urbanLifelineWeb/packages/platform/src/types/shared.d.ts index 24c3dae3..379edaf5 100644 --- a/urbanLifelineWeb/packages/platform/src/types/shared.d.ts +++ b/urbanLifelineWeb/packages/platform/src/types/shared.d.ts @@ -28,16 +28,13 @@ declare module 'shared/components/iframe/IframeView.vue' { export default IframeView } -declare module 'shared/components/iframe/IframeView.vue' { - import { DefineComponent } from 'vue' - const IframeView: DefineComponent<{}, {}, any> - export default IframeView -} - // ========== API 模块 ========== declare module 'shared/api' { export const api: any export const TokenManager: any + export const authAPI: any + export const fileAPI: any + export const workcaseAPI: any } declare module 'shared/api/auth' { @@ -48,26 +45,64 @@ declare module 'shared/api/file' { export const fileAPI: any } -declare module 'shared/api' { - export const authAPI: any - export const fileAPI: any - export const TokenManager: any - export const api: any +declare module 'shared/api/ai' { + export const agentAPI: any + export const aiKnowledgeAPI: any + export const aiChatAPI: any } -// 保留旧的导出路径(向后兼容) -declare module 'shared/FileUpload' { - import { DefineComponent } from 'vue' - const FileUpload: DefineComponent<{}, {}, any> - export default FileUpload +declare module 'shared/api/workcase' { + export const workcaseAPI: any } -declare module 'shared/DynamicFormItem' { - import { DefineComponent } from 'vue' - const DynamicFormItem: DefineComponent<{}, {}, any> - export default DynamicFormItem +// ============ types模块 ================== +declare module 'shared/types' { + import type { BaseDTO } from '../../../shared/src/types/base' + + // 重新导出 base + export type { BaseDTO } + + // 重新导出 response + export type { ResultDomain } from '../../../shared/src/types/response' + + // 重新导出 page + export type { PageDomain, PageParam, PageRequest } from '../../../shared/src/types/page' + + // 重新导出 auth + export type { LoginParam, LoginDomain } from '../../../shared/src/types/auth' + + // 重新导出 sys + export type { SysUserVO, SysConfigVO, TbSysViewDTO } from '../../../shared/src/types/sys' + + // 重新导出 file + export type { TbSysFileDTO } from '../../../shared/src/types/file' + + // 重新导出 ai + export type { + TbKnowledge, + TbKnowledgeFile, + TbAgent, + PromptCard, + TbChat, + TbChatMessage, + DifyFileInfo, + ChatPrepareData, + StopChatParams, + CommentMessageParams + } from '../../../shared/src/types/ai' + + // 重新导出 workcase + export type { + TbWorkcaseDTO, + TbWorkcaseProcessDTO, + TbWorkcaseDeviceDTO + } from '../../../shared/src/types/workcase' + + // 重新导出 menu + export type { MenuItem, toMenuItem, toMenuItems } from '../../../shared/src/types/menu' } +// ================ utils工具 ========================== declare module 'shared/utils' { export const initAesEncrypt: any export const getAesInstance: any @@ -78,47 +113,6 @@ declare module 'shared/utils' { export const getFilePreviewUrl: any } -declare module 'shared/types' { - import { RouteRecordRaw } from 'vue-router' - - export type LoginParam = any - export type LoginDomain = any - export type SysUserVO = any - export type TbSysFileDTO = any - export type SysConfigVO = any - export type ResultDomain = any - - // 视图类型(用于路由和菜单) - export interface TbSysViewDTO { - viewId?: string - name?: string - parentId?: string - url?: string - component?: string - iframeUrl?: string - icon?: string - type?: number - viewType?: string - service?: string - layout?: string - orderNum?: number - description?: string - children?: TbSysViewDTO[] - } - - // 菜单项类型(扩展 TbSysViewDTO) - export interface MenuItem extends TbSysViewDTO { - key: string - label: string - expanded?: boolean - children?: MenuItem[] - } - - // 菜单工具函数 - export function toMenuItem(view: TbSysViewDTO, expanded?: boolean): MenuItem - export function toMenuItems(views: TbSysViewDTO[], defaultExpanded?: boolean): MenuItem[] -} - declare module 'shared/utils/route' { import { RouteRecordRaw } from 'vue-router' import type { TbSysViewDTO } from 'shared/types' @@ -195,5 +189,4 @@ declare module 'shared/layouts' { export const BlankLayout: DefineComponent<{}, {}, any> export const SubSidebarLayout: DefineComponent<{}, {}, any> - } diff --git a/urbanLifelineWeb/packages/shared/src/api/ai/agent.ts b/urbanLifelineWeb/packages/shared/src/api/ai/agent.ts new file mode 100644 index 00000000..d20e3a89 --- /dev/null +++ b/urbanLifelineWeb/packages/shared/src/api/ai/agent.ts @@ -0,0 +1,68 @@ +import { api } from '@/api/index' +import type { ResultDomain, PageRequest } from '@/types' +import type { TbAgent } from '@/types/ai' + +/** + * @description 智能体管理接口 + * @filename agent.ts + * @author yslg + * @copyright xyzh + * @since 2025-12-19 + */ +export const agentAPI = { + baseUrl: '/urban-lifeline/ai/agent', + + /** + * 创建智能体 + * @param agent 智能体信息 + */ + async createAgent(agent: TbAgent): Promise> { + const response = await api.post(`${this.baseUrl}`, agent) + return response.data + }, + + /** + * 更新智能体 + * @param agent 智能体信息 + */ + async updateAgent(agent: TbAgent): Promise> { + const response = await api.put(`${this.baseUrl}`, agent) + return response.data + }, + + /** + * 删除智能体 + * @param agentId 智能体ID + */ + async deleteAgent(agentId: string): Promise> { + const response = await api.delete(`${this.baseUrl}/${agentId}`) + return response.data + }, + + /** + * 获取智能体详情 + * @param agentId 智能体ID + */ + async getAgent(agentId: string): Promise> { + const response = await api.get(`${this.baseUrl}/${agentId}`) + return response.data + }, + + /** + * 分页查询智能体 + * @param pageRequest 分页请求参数 + */ + async getAgentPage(pageRequest: PageRequest): Promise> { + const response = await api.post(`${this.baseUrl}/page`, pageRequest) + return response.data + }, + + /** + * 获取智能体列表 + * @param filter 筛选条件 + */ + async getAgentList(filter?: TbAgent): Promise> { + const response = await api.get(`${this.baseUrl}/list`, { params: filter }) + return response.data + } +} \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/api/ai/aiKnowledge.ts b/urbanLifelineWeb/packages/shared/src/api/ai/aiKnowledge.ts new file mode 100644 index 00000000..1e715c64 --- /dev/null +++ b/urbanLifelineWeb/packages/shared/src/api/ai/aiKnowledge.ts @@ -0,0 +1,262 @@ +import { api } from '@/api/index' +import type { ResultDomain, PageRequest } from '@/types' +import type { TbKnowledge, TbKnowledgeFile, SegmentRequestBody, DocumentStatusRequestBody } from '@/types/ai' + +/** + * @description AI知识库相关接口 + * @filename aiKnowledge.ts + * @author yslg + * @copyright xyzh + * @since 2025-12-19 + */ +export const aiKnowledgeAPI = { + baseUrl: '/urban-lifeline/ai/knowledge', + + // ====================== 知识库管理 ====================== + + /** + * 创建知识库 + * @param knowledge 知识库信息 + */ + async createKnowledge(knowledge: TbKnowledge): Promise> { + const response = await api.post(`${this.baseUrl}`, knowledge) + return response.data + }, + + /** + * 更新知识库 + * @param knowledge 知识库信息 + */ + async updateKnowledge(knowledge: TbKnowledge): Promise> { + const response = await api.put(`${this.baseUrl}`, knowledge) + return response.data + }, + + /** + * 删除知识库 + * @param knowledgeId 知识库ID + */ + async deleteKnowledge(knowledgeId: string): Promise> { + const response = await api.delete(`${this.baseUrl}/${knowledgeId}`) + return response.data + }, + + /** + * 获取知识库详情 + * @param knowledgeId 知识库ID + */ + async getKnowledge(knowledgeId: string): Promise> { + const response = await api.get(`${this.baseUrl}/${knowledgeId}`) + return response.data + }, + + /** + * 查询知识库列表 + * @param filter 筛选条件 + */ + async listKnowledges(filter?: TbKnowledge): Promise> { + const response = await api.post(`${this.baseUrl}/list`, filter || {}) + return response.data + }, + + /** + * 分页查询知识库 + * @param pageRequest 分页请求 + */ + async pageKnowledges(pageRequest: PageRequest): Promise> { + const response = await api.post(`${this.baseUrl}/page`, pageRequest) + return response.data + }, + + /** + * 获取知识库统计信息 + * @param knowledgeId 知识库ID + */ + async getKnowledgeStats(knowledgeId: string): Promise> { + const response = await api.get(`${this.baseUrl}/${knowledgeId}/stats`) + return response.data + }, + + // ====================== 文件管理 ====================== + + /** + * 获取知识库文档列表 + * @param knowledgeId 知识库ID + * @param page 页码 + * @param limit 每页条数 + */ + async getDocumentList(knowledgeId: string, page = 1, limit = 20): Promise>> { + const response = await api.get>(`${this.baseUrl}/${knowledgeId}/documents`, { + params: { page, limit } + }) + return response.data + }, + + /** + * 上传文件到知识库 + * @param file 文件 + * @param knowledgeId 知识库ID + * @param indexingTechnique 索引方式 + */ + async uploadToKnowledge( + file: File, + knowledgeId: string, + indexingTechnique?: string + ): Promise> { + const formData = new FormData() + formData.append('file', file) + formData.append('knowledgeId', knowledgeId) + if (indexingTechnique) { + formData.append('indexingTechnique', indexingTechnique) + } + const response = await api.upload(`${this.baseUrl}/file/upload`, formData) + return response.data + }, + + /** + * 批量上传文件到知识库 + * @param files 文件数组 + * @param knowledgeId 知识库ID + * @param indexingTechnique 索引方式 + */ + async batchUploadToKnowledge( + files: File[], + knowledgeId: string, + indexingTechnique?: string + ): Promise> { + const formData = new FormData() + files.forEach(file => formData.append('files', file)) + formData.append('knowledgeId', knowledgeId) + if (indexingTechnique) { + formData.append('indexingTechnique', indexingTechnique) + } + const response = await api.upload(`${this.baseUrl}/file/batch-upload`, formData) + return response.data + }, + + /** + * 更新知识库文件(上传新版本) + * @param file 文件 + * @param knowledgeId 知识库ID + * @param fileRootId 文件根ID + */ + async updateFile( + file: File, + knowledgeId: string, + fileRootId: string + ): Promise> { + const formData = new FormData() + formData.append('file', file) + formData.append('knowledgeId', knowledgeId) + formData.append('fileRootId', fileRootId) + const response = await api.uploadPut(`${this.baseUrl}/file/upload`, formData) + return response.data + }, + + /** + * 删除知识库文件 + * @param fileId 文件ID + */ + async deleteFile(fileId: string): Promise> { + const response = await api.delete(`${this.baseUrl}/file/${fileId}`) + return response.data + }, + + /** + * 获取文件历史版本 + * @param fileRootId 文件根ID + */ + async getFileHistory(fileRootId: string): Promise> { + const response = await api.get(`${this.baseUrl}/file/${fileRootId}/history`) + return response.data + }, + + // ====================== 文档分段管理 ====================== + + /** + * 获取文档分段列表 + * @param datasetId Dify数据集ID + * @param documentId Dify文档ID + */ + async getDocumentSegments(datasetId: string, documentId: string): Promise>> { + const response = await api.get>( + `${this.baseUrl}/datasets/${datasetId}/documents/${documentId}/segments` + ) + return response.data + }, + + /** + * 创建文档分段 + * @param datasetId Dify数据集ID + * @param documentId Dify文档ID + * @param requestBody 分段内容 + */ + async createSegment( + datasetId: string, + documentId: string, + requestBody: SegmentRequestBody + ): Promise> { + const response = await api.post( + `${this.baseUrl}/datasets/${datasetId}/documents/${documentId}/segments`, + requestBody + ) + return response.data + }, + + /** + * 更新文档分段 + * @param datasetId Dify数据集ID + * @param documentId Dify文档ID + * @param segmentId 分段ID + * @param requestBody 分段内容 + */ + async updateSegment( + datasetId: string, + documentId: string, + segmentId: string, + requestBody: SegmentRequestBody + ): Promise> { + const response = await api.patch( + `${this.baseUrl}/datasets/${datasetId}/documents/${documentId}/segments/${segmentId}`, + requestBody + ) + return response.data + }, + + /** + * 删除文档分段 + * @param datasetId Dify数据集ID + * @param documentId Dify文档ID + * @param segmentId 分段ID + */ + async deleteSegment( + datasetId: string, + documentId: string, + segmentId: string + ): Promise> { + const response = await api.delete( + `${this.baseUrl}/datasets/${datasetId}/documents/${documentId}/segments/${segmentId}` + ) + return response.data + }, + + // ====================== 文档状态管理 ====================== + + /** + * 更新文档状态(启用/禁用/归档) + * @param datasetId Dify数据集ID + * @param action 操作类型: enable/disable/archive/un_archive + * @param requestBody 请求体 + */ + async updateDocumentStatus( + datasetId: string, + action: 'enable' | 'disable' | 'archive' | 'un_archive', + requestBody: DocumentStatusRequestBody + ): Promise> { + const response = await api.patch( + `${this.baseUrl}/datasets/${datasetId}/documents/${action}/status`, + requestBody + ) + return response.data + } +} \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/api/ai/aichat.ts b/urbanLifelineWeb/packages/shared/src/api/ai/aichat.ts new file mode 100644 index 00000000..4820f611 --- /dev/null +++ b/urbanLifelineWeb/packages/shared/src/api/ai/aichat.ts @@ -0,0 +1,124 @@ +import { api } from '@/api/index' +import type { ResultDomain } from '@/types' +import type { TbChat, TbChatMessage, ChatPrepareData, StopChatParams, CommentMessageParams, DifyFileInfo } from '@/types/ai' + +/** + * @description AI对话相关接口 + * @filename aichat.ts + * @author yslg + * @copyright xyzh + * @since 2025-12-19 + */ +export const aiChatAPI = { + baseUrl: '/urban-lifeline/ai/chat', + + // ====================== 会话管理 ====================== + + /** + * 创建会话 + * @param chat 会话信息 + */ + async createChat(chat: TbChat): Promise> { + const response = await api.post(`${this.baseUrl}/conversation`, chat) + return response.data + }, + + /** + * 更新会话 + * @param chat 会话信息 + */ + async updateChat(chat: TbChat): Promise> { + const response = await api.put(`${this.baseUrl}/conversation`, chat) + return response.data + }, + + /** + * 删除会话 + * @param chat 会话信息 + */ + async deleteChat(chat: TbChat): Promise> { + const response = await api.delete(`${this.baseUrl}/conversation`, { data: chat }) + return response.data + }, + + /** + * 获取会话列表 + * @param filter 筛选条件 + */ + async getChatList(filter: TbChat): Promise> { + const response = await api.get(`${this.baseUrl}/conversations`, { data: filter }) + return response.data + }, + + // ====================== 消息管理 ====================== + + /** + * 获取对话消息列表 + * @param filter 筛选条件 + */ + async getMessageList(filter: TbChat): Promise> { + const response = await api.post(`${this.baseUrl}/messages`, filter) + return response.data + }, + + // ====================== 流式对话 ====================== + + /** + * 准备流式对话会话数据 + * @param chatPrepareData 对话预处理数据 + */ + async prepareStreamChat(chatPrepareData: ChatPrepareData): Promise> { + const response = await api.post(`${this.baseUrl}/stream/prepare`, chatPrepareData) + return response.data + }, + + /** + * 获取流式对话SSE URL + * @param sessionId 会话ID + */ + getStreamChatUrl(sessionId: string): string { + return `${this.baseUrl}/stream?sessionId=${sessionId}` + }, + + /** + * 创建流式对话 EventSource + * @param sessionId 会话ID + */ + createStreamChat(sessionId: string): EventSource { + const url = this.getStreamChatUrl(sessionId) + return new EventSource(url) + }, + + /** + * 停止对话 + * @param params 停止参数 + */ + async stopChat(params: StopChatParams): Promise> { + const response = await api.post(`${this.baseUrl}/stop`, params) + return response.data + }, + + /** + * 评价消息 + * @param params 评价参数 + */ + async commentMessage(params: CommentMessageParams): Promise> { + const response = await api.post(`${this.baseUrl}/comment`, params) + return response.data + }, + + // ====================== 文件上传 ====================== + + /** + * 上传文件用于对话(图文多模态) + * @param file 文件 + * @param agentId 智能体ID + */ + async uploadFileForChat(file: File, agentId: string): Promise> { + const formData = new FormData() + formData.append('file', file) + formData.append('agentId', agentId) + const response = await api.uploadPut(`${this.baseUrl}/file/upload`, formData) + return response.data + } +} \ No newline at end of file diff --git a/urbanLifelineWeb/packages/shared/src/api/ai/index.ts b/urbanLifelineWeb/packages/shared/src/api/ai/index.ts new file mode 100644 index 00000000..5a543c72 --- /dev/null +++ b/urbanLifelineWeb/packages/shared/src/api/ai/index.ts @@ -0,0 +1,3 @@ +export * from './agent' +export * from './aichat' +export * from './aiKnowledge' diff --git a/urbanLifelineWeb/packages/shared/src/api/index.ts b/urbanLifelineWeb/packages/shared/src/api/index.ts index 5c6edfbf..ff20b825 100644 --- a/urbanLifelineWeb/packages/shared/src/api/index.ts +++ b/urbanLifelineWeb/packages/shared/src/api/index.ts @@ -265,16 +265,17 @@ export const api = { }, /** - * 文件上传 + * 文件上传 (POST) - 使用 axios postForm */ upload(url: string, formData: FormData, config?: CustomAxiosRequestConfig): Promise>> { - return request.post>(url, formData, { - ...config, - headers: { - 'Content-Type': 'multipart/form-data', - ...(config?.headers as Record) - } - }); + return request.postForm>(url, formData, config); + }, + + /** + * 文件上传 (PUT) - 使用 axios putForm + */ + uploadPut(url: string, formData: FormData, config?: CustomAxiosRequestConfig): Promise>> { + return request.putForm>(url, formData, config); }, /** diff --git a/urbanLifelineWeb/packages/shared/src/api/workcase/index.ts b/urbanLifelineWeb/packages/shared/src/api/workcase/index.ts new file mode 100644 index 00000000..945f32a8 --- /dev/null +++ b/urbanLifelineWeb/packages/shared/src/api/workcase/index.ts @@ -0,0 +1 @@ +export * from './workcase' diff --git a/urbanLifelineWeb/packages/shared/src/api/workcase/workcase.ts b/urbanLifelineWeb/packages/shared/src/api/workcase/workcase.ts new file mode 100644 index 00000000..2416f7d4 --- /dev/null +++ b/urbanLifelineWeb/packages/shared/src/api/workcase/workcase.ts @@ -0,0 +1,185 @@ +import { api } from '@/api/index' +import type { ResultDomain, PageRequest } from '@/types' +import type { TbWorkcaseDTO, TbWorkcaseProcessDTO, TbWorkcaseDeviceDTO } from '@/types/workcase' + +/** + * @description 工单管理接口 + * @filename workcase.ts + * @author yslg + * @copyright xyzh + * @since 2025-12-19 + */ +export const workcaseAPI = { + baseUrl: '/urban-lifeline/workcase', + + // ========================= 工单管理 ========================= + + /** + * 创建工单 + * @param workcase 工单信息 + */ + async createWorkcase(workcase: TbWorkcaseDTO): Promise> { + const response = await api.post(`${this.baseUrl}`, workcase) + return response.data + }, + + /** + * 更新工单 + * @param workcase 工单信息 + */ + async updateWorkcase(workcase: TbWorkcaseDTO): Promise> { + const response = await api.put(`${this.baseUrl}`, workcase) + return response.data + }, + + /** + * 删除工单 + * @param workcaseId 工单ID + */ + async deleteWorkcase(workcaseId: string): Promise> { + const response = await api.delete(`${this.baseUrl}/${workcaseId}`) + return response.data + }, + + /** + * 获取工单详情 + * @param workcaseId 工单ID + */ + async getWorkcaseById(workcaseId: string): Promise> { + const response = await api.get(`${this.baseUrl}/${workcaseId}`) + return response.data + }, + + /** + * 查询工单列表 + * @param filter 筛选条件 + */ + async getWorkcaseList(filter?: TbWorkcaseDTO): Promise> { + const response = await api.post(`${this.baseUrl}/list`, filter || {}) + return response.data + }, + + /** + * 分页查询工单 + * @param pageRequest 分页请求 + */ + async getWorkcasePage(pageRequest: PageRequest): Promise> { + const response = await api.post(`${this.baseUrl}/page`, pageRequest) + return response.data + }, + + // ========================= CRM同步接口 ========================= + + /** + * 同步工单到CRM + * @param workcase 工单信息 + */ + async syncWorkcaseToCrm(workcase: TbWorkcaseDTO): Promise> { + const response = await api.post(`${this.baseUrl}/sync/crm`, workcase) + return response.data + }, + + /** + * 接收CRM工单更新(CRM回调) + * @param jsonBody JSON字符串 + */ + async receiveWorkcaseFromCrm(jsonBody: string): Promise> { + const response = await api.post(`${this.baseUrl}/receive/crm`, jsonBody) + return response.data + }, + + // ========================= 工单处理过程 ========================= + + /** + * 创建工单处理过程 + * @param process 处理过程信息 + */ + async createWorkcaseProcess(process: TbWorkcaseProcessDTO): Promise> { + const response = await api.post(`${this.baseUrl}/process`, process) + return response.data + }, + + /** + * 更新工单处理过程 + * @param process 处理过程信息 + */ + async updateWorkcaseProcess(process: TbWorkcaseProcessDTO): Promise> { + const response = await api.put(`${this.baseUrl}/process`, process) + return response.data + }, + + /** + * 删除工单处理过程 + * @param processId 处理过程ID + */ + async deleteWorkcaseProcess(processId: string): Promise> { + const response = await api.delete(`${this.baseUrl}/process/${processId}`) + return response.data + }, + + /** + * 查询工单处理过程列表 + * @param filter 筛选条件 + */ + async getWorkcaseProcessList(filter?: TbWorkcaseProcessDTO): Promise> { + const response = await api.post(`${this.baseUrl}/process/list`, filter || {}) + return response.data + }, + + /** + * 分页查询工单处理过程 + * @param pageRequest 分页请求 + */ + async getWorkcaseProcessPage(pageRequest: PageRequest): Promise> { + const response = await api.post(`${this.baseUrl}/process/page`, pageRequest) + return response.data + }, + + // ========================= 工单设备管理 ========================= + + /** + * 创建工单设备 + * @param device 设备信息 + */ + async createWorkcaseDevice(device: TbWorkcaseDeviceDTO): Promise> { + const response = await api.post(`${this.baseUrl}/device`, device) + return response.data + }, + + /** + * 更新工单设备 + * @param device 设备信息 + */ + async updateWorkcaseDevice(device: TbWorkcaseDeviceDTO): Promise> { + const response = await api.put(`${this.baseUrl}/device`, device) + return response.data + }, + + /** + * 删除工单设备 + * @param workcaseId 工单ID + * @param device 设备名称 + */ + async deleteWorkcaseDevice(workcaseId: string, device: string): Promise> { + const response = await api.delete(`${this.baseUrl}/device/${workcaseId}/${device}`) + return response.data + }, + + /** + * 查询工单设备列表 + * @param filter 筛选条件 + */ + async getWorkcaseDeviceList(filter?: TbWorkcaseDeviceDTO): Promise> { + const response = await api.post(`${this.baseUrl}/device/list`, filter || {}) + return response.data + }, + + /** + * 分页查询工单设备 + * @param pageRequest 分页请求 + */ + async getWorkcaseDevicePage(pageRequest: PageRequest): Promise> { + const response = await api.post(`${this.baseUrl}/device/page`, pageRequest) + return response.data + } +} diff --git a/urbanLifelineWeb/packages/shared/src/components/fileupload/FileUpload.vue b/urbanLifelineWeb/packages/shared/src/components/fileupload/FileUpload.vue index 4072128c..0e1e9a1f 100644 --- a/urbanLifelineWeb/packages/shared/src/components/fileupload/FileUpload.vue +++ b/urbanLifelineWeb/packages/shared/src/components/fileupload/FileUpload.vue @@ -169,6 +169,8 @@ interface Props { maxCount?: number title?: string buttonText?: string + // 自定义上传函数,如果提供则使用外部实现,否则使用默认上传逻辑 + customUpload?: (files: File[]) => Promise } const props = withDefaults(defineProps(), { @@ -178,7 +180,8 @@ const props = withDefaults(defineProps(), { maxSize: 10 * 1024 * 1024, maxCount: 10, title: '文件上传', - buttonText: '上传文件' + buttonText: '上传文件', + customUpload: undefined }) const emit = defineEmits<{ @@ -186,6 +189,8 @@ const emit = defineEmits<{ 'update:fileList': [value: TbSysFileDTO[]] 'upload-success': [files: TbSysFileDTO[]] 'upload-error': [error: string] + // 文件准备就绪事件,当使用自定义上传时触发,传递文件列表供外部处理 + 'files-ready': [files: File[]] }>() // 响应式数据 @@ -347,6 +352,41 @@ const handleDialogClose = (done: () => void) => { const uploadFiles = async () => { if (selectedFiles.value.length === 0) return + // 如果提供了自定义上传函数,则使用外部实现 + if (props.customUpload) { + uploading.value = true + try { + // 触发 files-ready 事件,传递文件列表 + emit('files-ready', [...selectedFiles.value]) + + // 调用自定义上传函数 + const result = await props.customUpload([...selectedFiles.value]) + + // 如果自定义函数返回了文件列表,触发上传成功事件 + if (result && result.length > 0) { + emit('upload-success', result) + emit('update:fileList', [...props.fileList, ...result]) + + if (props.mode === 'cover' && result[0]?.url) { + emit('update:coverImg', result[0].url) + } + } + + // 清空文件列表 + selectedFiles.value = [] + if (props.mode === 'dialog') { + closeDialog() + } + } catch (error) { + console.error('自定义上传失败:', error) + emit('upload-error', error instanceof Error ? error.message : '上传失败,请重试') + } finally { + uploading.value = false + } + return + } + + // 默认上传逻辑 uploading.value = true const uploadedFilesList: TbSysFileDTO[] = [] @@ -406,6 +446,29 @@ const uploadFiles = async () => { } } +// 暴露方法和状态供外部使用 +defineExpose({ + // 当前选中的文件列表 + selectedFiles, + // 上传状态 + uploading, + // 弹窗显示状态 + showDialog, + // 手动触发文件选择 + triggerFileInput, + // 手动添加文件 + addFiles, + // 移除指定文件 + removeFile, + // 清空所有文件 + clearFiles: () => { selectedFiles.value = [] }, + // 手动触发上传 + uploadFiles, + // 关闭弹窗 + closeDialog, + // 打开弹窗 + openDialog: () => { showDialog.value = true } +})