diff --git a/frontend-h5/.dockerignore b/frontend-h5/.dockerignore new file mode 100644 index 0000000..3be2309 --- /dev/null +++ b/frontend-h5/.dockerignore @@ -0,0 +1,4 @@ +node_modules +dist +.git +*.log diff --git a/frontend-h5/Dockerfile.dev b/frontend-h5/Dockerfile.dev index 34f8767..80c6878 100644 --- a/frontend-h5/Dockerfile.dev +++ b/frontend-h5/Dockerfile.dev @@ -16,7 +16,7 @@ WORKDIR /app COPY package.json pnpm-lock.yaml* ./ # 安装依赖 -RUN pnpm install --frozen-lockfile +RUN pnpm install --no-frozen-lockfile # 复制源码(后续通过 volume mount 更新) COPY . . diff --git a/frontend-h5/components.d.ts b/frontend-h5/components.d.ts index bf7df3c..9ea7d6a 100644 --- a/frontend-h5/components.d.ts +++ b/frontend-h5/components.d.ts @@ -14,7 +14,9 @@ declare module 'vue' { CallAgentModal: typeof import('./src/components/chat/CallAgentModal.vue')['default'] ChatPanel: typeof import('./src/components/chat/ChatPanel.vue')['default'] ComingSoon: typeof import('./src/components/assistant/ComingSoon.vue')['default'] + ConfidenceGateBanner: typeof import('./src/components/ConfidenceGateBanner.vue')['default'] EvaluationDialog: typeof import('./src/components/chat/EvaluationDialog.vue')['default'] + ImageUploader: typeof import('./src/components/ImageUploader.vue')['default'] InputBar: typeof import('./src/components/chat/InputBar.vue')['default'] InputBox: typeof import('./src/components/chat/InputBox.vue')['default'] MessageBubble: typeof import('./src/components/chat/MessageBubble.vue')['default'] @@ -28,16 +30,23 @@ declare module 'vue' { ScreenshotEditor: typeof import('./src/components/chat/ScreenshotEditor.vue')['default'] ShakeButton: typeof import('./src/components/chat/ShakeButton.vue')['default'] SoftwareDownloads: typeof import('./src/components/assistant/SoftwareDownloads.vue')['default'] + TriageCard: typeof import('./src/components/TriageCard.vue')['default'] TroubleshootFlow: typeof import('./src/components/chat/TroubleshootFlow.vue')['default'] TroubleshootProgress: typeof import('./src/components/chat/TroubleshootProgress.vue')['default'] VanButton: typeof import('vant/es')['Button'] + VanCell: typeof import('vant/es')['Cell'] + VanCellGroup: typeof import('vant/es')['CellGroup'] VanConfigProvider: typeof import('vant/es')['ConfigProvider'] VanDialog: typeof import('vant/es')['Dialog'] VanEmpty: typeof import('vant/es')['Empty'] VanField: typeof import('vant/es')['Field'] VanIcon: typeof import('vant/es')['Icon'] VanLoading: typeof import('vant/es')['Loading'] + VanNavBar: typeof import('vant/es')['NavBar'] VanPopup: typeof import('vant/es')['Popup'] VanRate: typeof import('vant/es')['Rate'] + VanStep: typeof import('vant/es')['Step'] + VanSteps: typeof import('vant/es')['Steps'] + VanTag: typeof import('vant/es')['Tag'] } } diff --git a/frontend-h5/index.html b/frontend-h5/index.html index 574ae73..49959b6 100644 --- a/frontend-h5/index.html +++ b/frontend-h5/index.html @@ -5,7 +5,7 @@ - + 智能IT支持服务台 diff --git a/frontend-h5/public/duckula.png b/frontend-h5/public/duckula.png new file mode 100644 index 0000000..5c90fe1 Binary files /dev/null and b/frontend-h5/public/duckula.png differ diff --git a/frontend-h5/public/duckula.webp b/frontend-h5/public/duckula.webp new file mode 100644 index 0000000..17d8a1f Binary files /dev/null and b/frontend-h5/public/duckula.webp differ diff --git a/frontend-h5/src/api/conversation.ts b/frontend-h5/src/api/conversation.ts index b2fab56..ab4d59e 100644 --- a/frontend-h5/src/api/conversation.ts +++ b/frontend-h5/src/api/conversation.ts @@ -173,8 +173,13 @@ export interface SoftwareDownload { export interface SendMessageResponse { /** 用户发送的消息 */ user_message: Message - /** AI 自动回复消息 */ - ai_reply: Message + /** + * AI 自动回复消息 + * 注意:改造方案 A 后,HTTP 接口不再同步返回 AI 回复(恒为 null), + * AI 回复由后台任务经 WebSocket 流式推回(ai_reply_chunk / ai_reply)。 + * 此处可能为 null,调用方(store)需改为依赖 WS 事件。 + */ + ai_reply: Message | null /** 是否为引导类回复(打招呼/呼叫人工),不计入实质回复 */ is_guidance: boolean /** 当前 AI 实质性回复计数 */ diff --git a/frontend-h5/src/api/index.ts b/frontend-h5/src/api/index.ts index 3843bc8..e1a2c6b 100644 --- a/frontend-h5/src/api/index.ts +++ b/frontend-h5/src/api/index.ts @@ -77,7 +77,7 @@ apiClient.interceptors.response.use( } // 业务成功:Scheme A — 直接返回 inner data(三端统一契约) - return res.data + return res.data as any }, async (error) => { // 网络错误或服务器错误:统一 reject {code, message}(CTRT-03) diff --git a/frontend-h5/src/api/troubleshooting-templates.ts b/frontend-h5/src/api/troubleshooting-templates.ts index d18d5c8..6f15430 100644 --- a/frontend-h5/src/api/troubleshooting-templates.ts +++ b/frontend-h5/src/api/troubleshooting-templates.ts @@ -7,7 +7,6 @@ // ============================================================================= import apiClient from './index' -import type { AxiosResponse } from 'axios' // -------------------------------------------------------------------------- // TypeScript 类型定义 — 与后端 Schema 保持一致 @@ -96,7 +95,7 @@ export interface TroubleshootingTemplateQuery { export async function getTroubleshootingTemplates( params?: TroubleshootingTemplateQuery, ): Promise { - const response: AxiosResponse = await apiClient.get('/troubleshooting-templates', { + const response = await apiClient.get('/troubleshooting-templates', { params: { category: params?.category || undefined, page: params?.page || 1, @@ -115,6 +114,6 @@ export async function getTroubleshootingTemplates( export async function getTroubleshootingTemplate( id: string, ): Promise { - const response: AxiosResponse = await apiClient.get(`/troubleshooting-templates/${id}`) + const response = await apiClient.get(`/troubleshooting-templates/${id}`) return response } diff --git a/frontend-h5/src/components/ConfidenceGateBanner.vue b/frontend-h5/src/components/ConfidenceGateBanner.vue new file mode 100644 index 0000000..a749fd1 --- /dev/null +++ b/frontend-h5/src/components/ConfidenceGateBanner.vue @@ -0,0 +1,331 @@ + + + + + + + diff --git a/frontend-h5/src/components/ImageUploader.vue b/frontend-h5/src/components/ImageUploader.vue new file mode 100644 index 0000000..f3c21dd --- /dev/null +++ b/frontend-h5/src/components/ImageUploader.vue @@ -0,0 +1,413 @@ + + +