商机智能助手项目总结

7 阅读7分钟

商机智能助手项目总结 - 面试准备

📋 项目概述

项目名称:商机智能助手(Agent Chat)
项目定位:面向房产经纪人的智能商机管理和分析平台
项目类型:移动端H5应用(主要运行在贝壳APP内)
开发模式:前后端分离,SPA单页应用


🛠️ 技术栈

核心技术

  • 框架:React 18.2.0(函数式组件 + Hooks)
  • 语言:TypeScript 5.6.3 + JavaScript (JSX)
  • 构建工具:Webpack 5.91.0
  • 编译工具:SWC(替代Babel,编译速度更快)
  • 路由:React Router DOM 6.26.2

UI框架

  • PC端组件库:Ant Design 5.18.1
  • 移动端组件库:Ant Design Mobile 5.39.0
  • 样式方案
    • Less(主要)
    • Sass/SCSS
    • Stylus
    • PostCSS + postcss-pxtorem(px转rem)

开发工具链

  • 代码规范
    • ESLint(Airbnb配置 + TypeScript支持)
    • Prettier(代码格式化)
    • Husky(Git Hooks)
    • lint-staged(提交前检查)
  • 类型检查:TypeScript(严格模式)
  • CSS处理:CSS-in-JS(@ant-design/cssinjs)

其他技术

  • 流式数据处理:SSE (Server-Sent Events) + @ant-design/x
  • 图表/可视化:html2canvas(截图功能)
  • 工具库:Lodash
  • 轮播组件:Swiper 11.2.10
  • Markdown渲染:markdown-it

✨ 项目亮点

1. 流式聊天实现(核心亮点)

  • 技术方案:使用SSE(Server-Sent Events)实现AI流式对话
  • 实现细节
    • 基于@ant-design/xuseXAgentuseXChat Hooks
    • 实时接收服务器推送的消息片段,逐字显示
    • 支持消息中断、重试机制
    • 区分prompt和普通消息类型,分别处理
  • 业务价值:提供类似ChatGPT的实时对话体验,提升用户体验
// 流式消息处理核心逻辑
onUpdate: (msg) => {
  if (msg.data && JSON.parse(msg.data).event === 'message') {
    const parseData = JSON.parse(msg.data);
    let { content, msgId, msgType } = parseData;
    // 区分prompt和普通消息,分别处理
    if (msgType === 'prompt') {
      currentContentObj.promptList.push(content);
    } else {
      contentText += content; // 逐字累加
    }
    onUpdate(currentContent);
  }
}

2. 完善的响应式布局方案

  • 自定义响应式工具类ResponsiveUtil
  • 实现原理
    • 基于设计稿宽度(375px)动态计算根字体大小
    • 监听窗口resize和orientationchange事件
    • 支持最小宽度(320px)和最大宽度(750px)限制
    • 提供px2rem、px2px等工具方法
  • 优势:一套代码适配多种移动设备,无需媒体查询

3. 多环境配置管理

  • 环境区分:development、test、preview、production
  • CDN配置:不同环境使用不同的CDN地址
  • 构建脚本build:productionbuild:testbuild:preview
  • 配置文件:独立的conf文件管理各环境配置

4. 完善的错误处理机制

  • 错误边界(Error Boundary):每个路由都配置了ErrorBoundary组件
  • 系统级加载器SystemLoader统一处理加载和错误状态
  • 用户上下文错误处理:UserContext中完善的错误捕获和重试机制
  • API错误统一处理responseHandler.js统一处理登录态、错误码等

5. TypeScript渐进式迁移

  • 混合开发:同时支持.tsx.jsx文件
  • 类型安全
    • API接口定义完整的TypeScript类型
    • 组件Props类型定义
    • 工具函数类型声明
  • 优势:在保持现有代码可用的同时,逐步提升代码质量

6. 性能优化

  • Webpack优化
    • 使用SWC替代Babel(编译速度提升)
    • 生产环境代码压缩(TerserPlugin)
    • CSS提取(MiniCssExtractPlugin)
    • 文件系统缓存(filesystem cache)
  • 代码分割:按路由进行代码分割
  • 资源优化:图片、字体等静态资源hash命名,支持CDN缓存

7. 与原生APP深度集成

  • JsBridge集成:通过JsBridgeV3与贝壳APP通信
  • 功能
    • 获取用户信息、token管理
    • 设置页面标题
    • Cookie域名管理
    • 埋点数据上报
  • 埋点系统:集成$ULOG埋点系统,支持页面和事件埋点

8. 组件化设计

  • 业务组件:高度封装的业务组件(如HomeInfoTaskEditModal等)
  • 通用组件:可复用的UI组件(如AppNavBarCommonFilter等)
  • 组件文档:部分组件包含README和demo文件

🎯 项目难点与解决方案

1. 流式消息的实时渲染和状态管理

难点

  • SSE连接的生命周期管理
  • 消息片段的累积和渲染
  • 用户中断请求的处理
  • 消息历史记录的保存和恢复

解决方案

  • 使用useRef保存当前消息内容,避免闭包问题
  • 通过abortRef管理请求中断
  • 区分消息类型(prompt/普通消息),分别处理
  • 使用useXChat Hook管理消息列表状态
// 中断处理
abortRef.current = async () => {
  setIsStopSse(true);
  onSuccess(currentContent); // 清空长链接队列
};

2. 移动端适配的复杂性

难点

  • 不同设备尺寸适配
  • 横竖屏切换
  • 安全区域适配(刘海屏、底部安全区)
  • 字体大小和间距的精确控制

解决方案

  • 自定义响应式工具类,统一管理根字体大小
  • 使用rem单位,配合postcss-pxtorem自动转换
  • 监听orientationchange事件,及时更新布局
  • 设置合理的minWidth和maxWidth限制

3. 多环境配置和构建优化

难点

  • 不同环境需要不同的API地址、CDN地址
  • 构建产物需要区分环境
  • 开发、测试、预发、生产环境的配置管理

解决方案

  • 使用cross-env设置环境变量
  • Webpack的DefinePlugin注入环境变量
  • 独立的配置文件(conf目录)
  • 不同环境的构建脚本

4. 用户权限和角色管理

难点

  • 多角色切换(门店管理者、普通经纪人等)
  • 权限校验和页面访问控制
  • 用户信息获取失败的处理

解决方案

  • 使用Context API(UserContext)全局管理用户状态
  • 系统级加载器(SystemLoader)统一处理加载和错误
  • 完善的错误提示和重试机制
  • 角色选择弹窗,支持动态切换

5. 复杂表单的状态管理

难点

  • 任务编辑弹窗包含多个联动选择器
  • 表单验证和预览功能
  • 编辑和新增模式的区分

解决方案

  • 使用useStateuseMemo管理复杂表单状态
  • 组件化设计,将选择器封装为独立组件(InfoSelector
  • 使用useCallback优化回调函数性能
  • 清晰的类型定义,保证数据一致性

6. 页面状态的多条件判断

难点

  • 首页根据API返回的statusType展示不同组件
  • 加载、错误、空数据等多种状态的统一管理
  • 状态切换时的埋点上报

解决方案

  • 使用状态机模式,统一管理页面状态
  • 条件渲染,根据状态展示对应组件
  • useCallback封装埋点函数,避免重复创建
  • 清晰的类型定义(PageStatusHomeState

实现sse hook封装

import { useCallback, useRef, useState, useEffect } from 'react';

interface SSEChatOptions {
  /** 基础地址,如:/sseApi/api/chat/stream */
  baseURL: string;
}

interface SSEMessage {
  id?: string;
  content: string;
  raw?: any;
}

export function useSSEChat(options: SSEChatOptions) {
  const { baseURL } = options;

  const [messages, setMessages] = useState<SSEMessage[]>([]);
  const [isStreaming, setIsStreaming] = useState(false);
  const [error, setError] = useState<Error | null>(null);

  // 当前 EventSource 实例
  const eventSourceRef = useRef<EventSource | null>(null);
  // 当前累积的回复内容(类似你项目里的 currentContent)
  const currentContentRef = useRef<string>('');

  const closeEventSource = useCallback(() => {
    if (eventSourceRef.current) {
      eventSourceRef.current.close();
      eventSourceRef.current = null;
    }
    setIsStreaming(false);
  }, []);

  // 发送问题并建立 SSE 连接
  const sendMessage = useCallback(
    (query: string) => {
      // 每次新问题先关掉旧连接
      closeEventSource();
      setError(null);
      currentContentRef.current = '';

      // 一般 SSE 用 GET + query 参数,这里简单拼一下
      const url = `${baseURL}?query=${encodeURIComponent(query)}&stream=true`;

      const es = new EventSource(url);
      eventSourceRef.current = es;
      setIsStreaming(true);

      es.onopen = () => {
        // console.log('SSE 连接已建立');
      };

      es.onerror = (e: any) => {
        setError(new Error('SSE 连接出错'));
        closeEventSource();
      };

      es.onmessage = (event: MessageEvent) => {
        try {
          // 和你项目类似,后端通常发 JSON 字符串
          const data = JSON.parse(event.data);

          // 示例:后端有 event 字段 / msgType / content 等
          if (data.event && data.event !== 'message') return;
          const { content, msgId, msgType } = data;

          // 结束信号
          if (content === 'connected' || content === 'completed') {
            closeEventSource();
            return;
          }

          // 累加内容(你也可以按 msgType 拆分 prompt / content)
          currentContentRef.current += content ?? '';

          // 更新 React 状态(这里简单以“最后一条回复”为例)
          setMessages((prev) => {
            const last = prev[prev.length - 1];
            if (last && last.id === msgId) {
              // 更新最后一条
              const newLast: SSEMessage = {
                ...last,
                content: currentContentRef.current,
                raw: data,
              };
              return [...prev.slice(0, -1), newLast];
            }
            // 新增一条消息
            return [
              ...prev,
              {
                id: msgId,
                content: currentContentRef.current,
                raw: data,
              },
            ];
          });
        } catch (err) {
          console.error('解析 SSE 消息失败', err);
        }
      };
    },
    [baseURL, closeEventSource],
  );

  // 手动停止流
  const stop = useCallback(() => {
    closeEventSource();
  }, [closeEventSource]);

  // 组件卸载时清理
  useEffect(() => {
    return () => {
      closeEventSource();
    };
  }, [closeEventSource]);

  return {
    messages,
    isStreaming,
    error,
    sendMessage,
    stop,
  };
}

📊 项目架构

目录结构

src/
├── apis/              # API接口层
│   ├── interface/     # TypeScript接口定义
│   └── services/     # API服务实现
├── components/        # 组件库
│   ├── HomeInfo/     # 业务组件
│   ├── TaskEditModal/# 通用组件
│   └── ...
├── pages/            # 页面组件
│   ├── Home/         # 首页
│   ├── agentChatH5/  # AI聊天页
│   └── ...
├── contexts/          # Context API
│   └── UserContext.jsx
├── hooks/            # 自定义Hooks
├── utils/            # 工具函数
│   ├── request.ts    # HTTP请求封装
│   ├── responsive.js # 响应式工具
│   └── ...
└── config/           # 配置文件
    └── routes.jsx    # 路由配置

数据流

  1. 用户信息流:UserContext → SystemLoader → 路由组件
  2. API数据流:services → request.ts → responseHandler → 组件
  3. 状态管理:组件内部useState + Context API全局状态

🚀 性能优化实践

  1. 编译优化:SWC替代Babel,编译速度提升3-5倍
  2. 代码分割:按路由懒加载,减少首屏加载时间
  3. 资源优化:图片、字体等静态资源CDN加速
  4. 缓存策略:Webpack filesystem cache,二次构建速度提升
  5. React优化
    • 使用useMemouseCallback避免不必要的重渲染
    • 组件拆分,减少单组件复杂度

🔒 代码质量保障

  1. 类型安全:TypeScript类型检查
  2. 代码规范:ESLint + Prettier
  3. Git Hooks:Husky + lint-staged,提交前自动检查
  4. 错误处理:完善的错误边界和异常捕获
  5. 代码审查:组件文档和注释规范

📱 业务功能模块

  1. 智能聊天:AI助手对话,流式消息展示
  2. 首页诊断:门店数据分析和诊断报告
  3. 任务管理:任务下发、执行、编辑
  4. 商机跟进:商机列表、跟进记录
  5. 数据分析:门店转化、用户行为分析
  6. 经纪人管理:经纪人信息管理
  7. IM质量报告:IM沟通质量分析

💡 面试重点问题准备

Q1: 为什么选择SWC而不是Babel?

:SWC是用Rust编写的,编译速度比Babel快10-100倍,同时支持TypeScript和JSX,能够显著提升开发体验和构建速度。

Q2: 流式聊天是如何实现的?

:使用SSE(Server-Sent Events)技术,通过@ant-design/x的Hooks封装,实时接收服务器推送的消息片段,使用useRef保存当前消息内容,通过onUpdate回调逐字更新UI,支持消息中断和重试机制。

Q3: 移动端适配方案?

:自定义响应式工具类,基于设计稿宽度(375px)动态计算根字体大小,使用rem单位配合postcss-pxtorem自动转换,监听窗口变化事件,设置合理的宽度限制。

Q4: 如何处理多环境配置?

:使用cross-env设置环境变量,Webpack的DefinePlugin注入到代码中,不同环境使用不同的CDN地址和API地址,独立的配置文件管理。

Q5: 错误处理机制?

:路由级错误边界、系统级加载器、API统一错误处理、用户上下文错误捕获,完善的错误提示和重试机制。

Q6: 性能优化做了哪些工作?

:SWC编译优化、代码分割、资源CDN、Webpack缓存、React性能优化(useMemo、useCallback)、组件拆分。


📝 项目总结

这是一个技术栈现代化、架构清晰、业务复杂的移动端H5项目。项目在以下方面表现突出:

  1. 技术选型合理:React 18 + TypeScript + Webpack 5,使用SWC提升构建速度
  2. 用户体验优秀:流式聊天、响应式布局、完善的错误处理
  3. 代码质量高:TypeScript类型安全、ESLint规范、完善的错误处理
  4. 工程化完善:多环境配置、Git Hooks、性能优化

项目规模:10+页面,20+组件,完善的API层和工具函数库

技术难点:流式数据处理、移动端适配、复杂状态管理、多环境配置


🎓 学习收获

  1. 深入理解React Hooks:useState、useEffect、useCallback、useMemo等
  2. SSE流式数据处理:实时通信的实现和优化
  3. 移动端适配方案:rem布局、响应式设计
  4. 工程化实践:Webpack配置、多环境管理、代码规范
  5. TypeScript实践:类型定义、接口设计、渐进式迁移

最后更新:2024年