Vue3 + TypeScript 实战:打造企业级工单管理系统(列表+详情+时间轴交互)

Vue3 + TypeScript 实战:打造企业级工单管理系统(列表+详情+时间轴交互)

在客户服务与内部运维场景中,一个高效的工单管理系统是连接用户与管理者的桥梁。如何清晰展示工单流转过程?如何实现流畅的回复与状态变更?

本文将深入剖析一套基于 Vue3 + TypeScript + Ant Design Vue 的工单管理模块。我们将重点讲解多维筛选列表沉浸式时间轴详情页富文本回复 以及状态机流转的核心实现逻辑。


🎯 核心功能概览

本系统包含两大核心视图:

  1. 工单列表页:支持按创建/更新时间、状态、关键字、发布人等多维度筛选,具备自定义列宽、排序及快速预览功能。
  2. 工单详情页:采用垂直时间轴展示沟通记录,支持富文本回复、附件上传/预览、一键转知识库及灵活的状态变更(待回复/处理中/已完成)。

🏗️ 架构设计亮点

1. 智能筛选与防抖搜索

列表页提供了复杂的筛选条件,包括动态切换的时间类型(创建时间 vs 更新时间)和多种状态组合。为了避免频繁请求接口,所有搜索操作均加入了**防抖(Debounce)**机制。

typescript 复制代码
// 防抖搜索:500ms 内多次触发只执行最后一次
const debounceSearch = debounce(onSearch, 500);
const debounceReset = debounce(onReset, 500);

const onSearch = () => {
  data.pagination.current = 1; // 重置页码
  findWorkOrderList();
};

// 动态时间范围处理
const findWorkOrderList = async () => {
  const params = {
    ...data.searchObj,
    // 根据选择的时间类型映射字段
    startTime: data.dates?.[0] || null,
    endTime: data.dates?.[1] || null,
    page: data.pagination.current,
    pageSize: data.pagination.pageSize,
  };
  // ... 发起请求
};

UI 细节

  • 使用 a-dropdown 自定义时间类型选择器,动态改变 a-range-picker 的语义。
  • "等待回复"复选框独立存在,方便管理员快速定位急需处理的工单。

2. 沉浸式时间轴详情页

详情页没有使用通用的 Steps 组件,而是定制开发了垂直沟通时间轴,清晰区分"咨询人"与"处理人"的角色,并通过不同的图标状态(进行中/已完成)直观展示流程。

vue 复制代码
<template>
  <div class="detail-header-view">
    <div v-for="(item, index) in data.dataSource" :key="item.id" class="detail-header-view-item">
      <!-- 左侧轴线与节点 -->
      <div class="detail-header-view-item-left">
        <!-- 动态渲染虚线连接线 -->
        <span class="detail-header-view-item-left-second-line"></span>
        <!-- 动态渲染节点图标:咨询/处理/完成 -->
        <span class="detail-header-view-item-left-circle-dot">
          <img :src="getItemIcon(item)" alt="">
        </span>
      </div>
      
      <!-- 右侧内容卡片 -->
      <div class="detail-header-view-item-right">
        <div class="detail-header-view-item-right-top-title">
          {{ item.type === 1 ? '咨询人' : '处理人' }}
        </div>
        <!-- 内容支持长文本省略与展开 -->
        <van-text-ellipsis rows="2" :content="item.contentText">
          <template #action><span @click="handleSeeAll($event, item)">查看全部</span></template>
        </van-text-ellipsis>
        
        <!-- 特色功能:添加到知识库 -->
        <div class="detail-header-view-item-right-add-knowledge" @click="handleAddToKnowledge(item)">
          <i class="iconfont icon-book"></i> 问答内容添加到知识库
        </div>
      </div>
    </div>
  </div>
</template>

交互亮点

  • 角色区分 :通过 item.type 自动切换左右布局逻辑和图标样式。
  • 长文本处理 :集成 van-text-ellipsis,默认显示两行,点击"查看全部"弹出模态框展示完整富文本内容。
  • 知识沉淀:每条回复记录都提供"添加到知识库"入口,助力构建企业 FAQ 库。

3. 富文本回复与附件管理

底部回复区集成了自定义富文本编辑器,支持图文混排,并实现了附件的上传、预览、下载及删除功能。

typescript 复制代码
// 自定义上传逻辑
const customRequest = async (info) => {
  // 1. 文件名长度校验
  if (info.file.name.length > 100) {
    Modal.warning({ content: '文件名称长度限制在 100 字符以内' });
    return;
  }
  // 2. 调用上传接口
  const [err, res] = await to(SingleUploadFile(info.file));
  if (!err && res) {
    // 3. 存入临时列表,待提交时一并发送
    data.tempFileList.push({
      id: res.data.id,
      name: res.data.OldFileName,
      path: res.data.FileUrl,
    });
  }
};

// 提交回复
const handleReply = async () => {
  const params = {
    workOrderId: data.workOrderId,
    sendContentHtml: richEditorRef.value.getHtmlValue(),
    sendContentText: richEditorRef.value.getContentValue(),
    annexIdList: data.tempFileList.map(item => item.id), // 关联附件 ID
  };
  await StaffReplyWorkOrderInfo(params);
  // 成功后刷新时间轴
};

细节优化

  • 附件列表项 Hover 时显示删除按钮,保持界面整洁。
  • 提交前自动校验内容非空。
  • 支持图片、文档等多种格式的在线预览与下载。

4. 灵活的状态机流转

工单状态管理是核心业务逻辑。系统支持在详情页顶部通过下拉菜单灵活变更状态,并在回复时自动触发状态流转。

  • 手动变更:管理员可通过右上角下拉框将工单标记为"待回复"、"处理中"或"已完成"。
  • 自动流转
    • 回复工单后,状态自动变为 "处理中"
    • 若原状态为"已完成",管理员再次回复后,状态自动回滚为 "处理中",确保流程闭环。
    • 标记"已完成"后,用户端将不可再回复。
typescript 复制代码
const handleDetailMenuClick = (e: any) => {
  // 映射 Key 到状态文本和数值
  data.orderDetailState = e.key === '1' ? '待回复' : e.key === '2' ? '处理中' : '已完成';
  updateWorkOrderStatus();
};

// 回复成功后的回调
if (data.workOrderState === 3) { // 3 = 已完成
  data.workOrderState = 2; // 自动变回处理中
  emit('changeOrderState'); // 通知父组件更新列表标签
}

💡 关键代码片段解析

自定义列宽与排序

表格支持拖拽调整列宽和后端排序,提升大数据量下的浏览体验。

typescript 复制代码
// 列宽调整
const handleResizeColumn = (w: number, col: any) => {
  data.columns.forEach(item => {
    if (item.key === col.key) item.width = w;
  });
};

// 排序参数转换
const onChange = (pagination, filters, sorter) => {
  if (sorter.field) {
    data.searchObj.sortField = sorter.field === 'lastUpdateTime' ? 1 : 2;
    data.searchObj.sortType = sorter.order === 'ascend' ? 'ASC' : 'DESC';
  }
  debounceChangeOrderList();
};

安全的删除确认

使用 Modal.confirm 配合 h 函数自定义图标和样式,防止误操作。

typescript 复制代码
const handleDetailDelete = () => {
  Modal.confirm({
    icon: () => h(ExclamationCircleFilled, { style: 'color:red;font-size: 18px;' }),
    content: '确定要删除该工单吗?一旦移除,数据将无法恢复',
    onOk: () => updateWorkOrderStatus(true), // true 表示删除
  });
};

📊 效果展示

  • 📋 高效列表:多维度筛选、自定义列宽、状态标签高亮、Tooltip 快速预览最新回复。
  • ⏳ 清晰轨迹:垂直时间轴完美还原沟通上下文,咨询/回复角色一目了然。
  • 📝 便捷回复:富文本编辑、附件拖拽上传、一键转知识库,提升处理效率。
  • 🔄 状态闭环:灵活的手动/自动状态流转机制,确保工单生命周期管理规范有序。

✅ 总结

本工单管理系统不仅实现了基础的 CRUD 功能,更在用户体验业务逻辑闭环上做了深度优化。

  1. 可视化强:时间轴设计让沟通历史清晰可追溯。
  2. 交互友好:防抖搜索、列宽拖拽、长文本省略等细节提升了操作舒适度。
  3. 业务赋能:内置"转知识库"功能,将单次服务转化为长期资产。

这套方案适用于IT 运维、客户支持、行政审批等多种场景,可直接复用或作为企业级后台的开发模板。

💡 提示:在实际生产中,建议增加工单超时提醒、SLA 统计看板以及更细粒度的权限控制(如仅分配人可回复)。


技术栈 :Vue3 | TypeScript | Ant Design Vue | Vant Utils (TextEllipsis)
适用场景:客服系统、ITSM、OA 办公、售后支持

如果你觉得这篇文章对你有帮助,欢迎点赞、收藏!有任何关于时间轴绘制或状态机设计的问题,欢迎在评论区交流~