本文档详细梳理了客服板块和管理员板块的功能模块、操作流程、角色权限和数据字段,为产品复盘和功能优化提供完整的参考依据。
/customer-service/dashboard)数据统计卡片(5个核心指标):
| 指标名称 | 数据来源 | 计算逻辑 | 点击操作 |
|---|---|---|---|
| 项目总数 | Project 表 |
count() 查询所有项目 |
跳转到项目列表(显示全部) |
| 新咨询数 | Project 表 |
今日新增项目数(createdAt >= 今日0点) |
- |
| 待分配项目 | Project 表 |
currentStage 为订单分配阶段的项目数 |
跳转到项目列表(筛选待分配) |
| 异常项目 | Project 表 |
超期项目数(deadline < 当前时间 且状态为进行中) |
- |
| 售后服务 | ProjectFeedback 表 |
类型为投诉且状态为待处理的反馈数 | - |
数据表结构:
// Project 表字段
{
title: string; // 项目名称
currentStage: string; // 当前阶段(订单分配/确认需求/交付执行/售后归档)
status: string; // 状态(待分配/进行中/已完成)
deadline: Date; // 截止时间
createdAt: Date; // 创建时间
company: Pointer; // 所属公司
contact: Pointer; // 客户信息
assignee: Pointer; // 负责人
}
功能描述:显示处于售后归档阶段且有未付尾款的项目列表
数据来源:
Project 表,筛选 currentStage 为售后归档相关阶段Project.data 字段读取支付信息(不使用 ProjectPayment 表)显示字段:
{
projectName: string; // 项目名称
customerName: string; // 客户姓名
customerPhone: string; // 客户电话
finalPaymentAmount: number; // 剩余未付金额
totalAmount: number; // 订单总金额
paidAmount: number; // 已付金额
dueDate: Date; // 到期日期
status: string; // 状态(已逾期/待创建/待付款)
overdueDay: number; // 逾期天数
}
操作路径:
/wxwork/:cid/project/:projectId/aftercare)功能描述:自动计算并显示截止时间已到或即将到达但未完成的关键节点
计算逻辑(复用组长端逻辑):
// 紧急事件类型
{
type: 'review' | 'delivery' | 'deadline'; // 小图对图/交付审批/项目截止
projectId: string;
projectName: string;
deadline: Date;
urgencyLevel: 'critical' | 'high' | 'medium';
description: string;
}
紧急程度判断:
操作路径:
功能描述:显示从问题板块加载的待办任务(待处理+处理中状态)
数据来源:ProjectIssue 表
数据结构:
{
id: string;
title: string; // 问题标题
description: string; // 问题描述
status: '待处理' | '处理中' | '已解决' | '已关闭';
priority: '紧急' | '高' | '中' | '低';
projectId: string;
projectName: string;
creator: Pointer; // 创建人
assignee: Pointer; // 负责人
createdAt: Date;
updatedAt: Date;
}
操作功能:
/customer-service/case-library)数据来源:Case 表(从已完成项目自动生成)
案例数据结构:
{
id: string;
name: string; // 案例名称
projectId: string; // 关联项目ID
projectName: string; // 项目名称
designer: string; // 设计师姓名
designerId: string;
team: string; // 团队名称
teamId: string;
coverImage: string; // 封面图
images: string[]; // 案例图片
area: number; // 面积
projectType: '工装' | '家装';
spaceType: '平层' | '复式' | '别墅' | '自建房';
renderingLevel: '高端' | '中端' | '低端';
tag: string[]; // 风格标签
totalPrice: number; // 项目总额
completionDate: Date; // 完成时间
viewCount: number; // 浏览次数
shareCount: number; // 分享次数
favoriteCount: number; // 收藏次数
isExcellent: boolean; // 是否优秀案例
isPublished: boolean; // 是否发布
}
统计按钮位置:页面头部右侧(案例总数和本月新增统计卡片旁边)
三大统计维度:
Top 5 分享案例
shareCount 降序排序,取前5名客户最喜欢风格
tag 标签,按 favoriteCount 累加设计师推荐率
推荐率 = (优秀案例数 / 总案例数) × 100%isExcellent = true筛选条件:
分页:每页显示12个案例(3列×4行)
/customer-service/project-list)1. 卡片视图(看板)
2. 列表视图
3. 监控大盘
视图切换:
{
id: string;
name: string; // 项目名称
customerName: string; // 客户姓名
customerId: string;
assigneeName: string; // 负责人姓名
assigneeId: string;
currentStage: string; // 当前阶段
status: string; // 状态
deadline: Date; // 截止时间
progress: number; // 进度(0-100)
daysUntilDeadline: number; // 距离截止天数
isUrgent: boolean; // 是否紧急
tagDisplayText: string; // 标签显示文本
createdAt: Date;
updatedAt: Date;
}
点击项目卡片:
enterFromCustomerService = '1'/wxwork/:cid/project/:projectId/:stage操作步骤:
AI分析功能:
数据存储:
// ProjectFile 表
{
fileName: string;
fileUrl: string;
fileSize: number;
fileType: string; // 'image' | 'cad' | 'document'
category: string; // 'soft_decor' | 'hard_decor' | 'cad' | 'other'
projectId: string;
productId: string; // 空间ID
stage: 'requirements';
uploadedBy: Pointer;
uploadedAt: Date;
analysisResult: object; // AI分析结果
}
全局需求:
空间需求(按空间分别填写):
操作路径:
AIService.generateDesignSolution()生成内容:
{
overallStyle: string; // 整体风格定位
colorScheme: {
primary: string; // 主色调
secondary: string; // 副色调
accent: string; // 点缀色
};
materialRecommendations: string[]; // 材质推荐
layoutOptimization: string[]; // 布局优化建议
budgetAssessment: {
estimatedMin: number;
estimatedMax: number;
riskLevel: string;
};
timeline: string; // 预计工期
riskFactors: string[]; // 风险因素
spaceSolutions: Array<{ // 各空间方案
name: string;
styleDescription: string;
colorPalette: string[];
materials: string[];
furnitureRecommendations: string[];
}>;
}
功能描述:AI聊天助手,回答家装设计相关问题
操作路径:
实现:
操作路径:
操作步骤:
drag-upload-modal 组件AI分析服务:
ImageAnalysisServicefmode-1.6-cn)弹窗显示:
┌─────────────────────────────────────┐
│ AI智能识别上传弹窗 │
├─────────────────────────────────────┤
│ 文件 │ 名称 │ 上传 │ 空间 │ 阶段 │
├─────────────────────────────────────┤
│ [图] │ xxx.jpg │ 完成 │ 客厅 │ 软装 │
│ [图] │ yyy.png │ 完成 │ 卧室 │ 渲染 │
├─────────────────────────────────────┤
│ [撤回] [确认交付清单] │
└─────────────────────────────────────┘
操作路径:
记录信息:
// Project.data.spaceConfirmations
{
[spaceId]: {
confirmedBy: string; // 确认人ID
confirmedByName: string; // 确认人姓名
confirmedByRole: string; // 确认人角色
confirmedAt: Date; // 确认时间
filesSnapshot: string[]; // 文件ID快照
}
}
操作路径:
审批状态记录:
// Project.data.deliveryApproval
{
status: 'pending'; // 待审批
stage: 'delivery';
totalFiles: number;
types: { // 各类型文件数量
white_model: number;
soft_decor: number;
rendering: number;
post_process: number;
};
submittedAt: Date;
submittedByName: string;
submittedById: string;
}
操作步骤:
AI提取逻辑:
数据存储:
// Project.data.payments
{
voucherUrl: string; // 凭证图片URL
amount: number; // 支付金额
extractedAmount: number; // AI提取的金额
uploadedBy: string;
uploadedAt: Date;
type: 'deposit' | 'progress' | 'final'; // 定金/进度款/尾款
}
功能描述:点击凭证图片可放大预览
显示信息:
默认值:报价总金额(从订单分配阶段获取)
计算逻辑:
totalAmount = 报价总金额;
paidAmount = sum(所有支付凭证金额);
remainingAmount = totalAmount - paidAmount;
/admin/dashboard)6大核心指标:
| 指标名称 | 数据来源 | 计算逻辑 | 点击操作 |
|---|---|---|---|
| 总项目数 | Project 表 |
count() 所有项目 |
展开项目明细面板 |
| 进行中项目 | Project 表 |
根据 currentStage 自动判断状态为"进行中" |
展开进行中项目明细 |
| 已完成项目 | Project 表 |
currentStage 为售后归档阶段自动标记为已完成 |
展开已完成项目明细 |
| 设计师总数 | Profile 表 |
roleName = '组员' 的员工数 |
展开设计师明细 |
| 客户总数 | ContactInfo 表 |
count() 所有客户 |
展开客户明细 |
| 总收入 | Project.data |
从售后归档项目中累加已支付尾款 | 展开收入明细 |
状态自动判断逻辑:
function getProjectStatusByStage(stageId: string, currentStatus?: string): string {
// 如果已经是完成或取消状态,保持不变
if (currentStatus === '已完成' || currentStatus === '已取消') {
return currentStatus;
}
const corePhase = mapStageToCorePhase(stageId);
switch (corePhase) {
case 'order':
return '待分配';
case 'requirements':
case 'delivery':
return '进行中';
case 'aftercare':
return '已完成'; // 售后归档自动标记为已完成
default:
return '待分配';
}
}
1. 项目趋势图(ECharts折线图)
2. 收入趋势图(ECharts柱状图)
点击统计卡片后展开侧边抽屉,显示详细数据:
项目明细:
设计师明细:
客户明细:
/admin/project-management)数据查询:
// 查询逻辑
const projects = await ProjectService.findProjects({
status: statusFilter, // 状态筛选
keyword: searchTerm, // 关键词搜索
skip: currentPage * pageSize,
limit: pageSize
});
// Include关联数据
include: ['contact', 'customer', 'assignee', 'department', 'department.leader']
显示字段:
assignee,其次从 ProjectTeam 表获取)操作路径:
显示内容:
操作路径:
分配逻辑:
// 更新 Project.assignee(主要负责人)
project.set('assignee', {
__type: 'Pointer',
className: 'Profile',
objectId: mainDesignerId
});
// 保存所有分配的设计师到 Project.data
project.set('data', {
...data,
assignedDesigners: [designerId1, designerId2, ...],
crossTeamCollaborators: [...],
primaryTeamId: teamId
});
// 创建 ProjectTeam 记录
const projectTeam = new ProjectTeam();
projectTeam.set('project', project.toPointer());
projectTeam.set('profile', designer.toPointer());
projectTeam.set('role', 'primary' | 'collaborator');
await projectTeam.save();
筛选条件:
排序字段:
分页:每页10条
/admin/departments)数据来源:Department 表
数据结构:
{
id: string;
name: string; // 项目组名称
leader: Pointer; // 组长(Profile)
leaderName: string; // 组长姓名
type: 'project'; // 类型
memberCount: number; // 成员数量
createdAt: Date;
isDeleted: boolean;
}
显示字段:
操作路径:
roleName = '组长')创建逻辑:
const dept = await DepartmentService.createDepartment({
name: '设计一组',
leaderId: 'profileId',
type: 'project'
});
// 同时更新组长的 department 字段
const profile = await Parse.Query('Profile').get(leaderId);
profile.set('department', dept.toPointer());
await profile.save();
可编辑字段:
操作路径:
删除方式:软删除(设置 isDeleted = true)
操作路径:
注意事项:
操作路径:
显示内容:
/admin/employees)数据来源:Profile 表(从企微同步)
数据结构:
{
id: string;
name: string; // 昵称(内部沟通用)
realname: string; // 真实姓名
mobile: string; // 手机号
userid: string; // 企微ID
roleName: string; // 身份(组长/组员/客服/管理员)
department: Pointer; // 所属部门
departmentName: string; // 部门名称
isDisabled: boolean; // 是否禁用
avatar: string; // 头像
email: string; // 邮箱
position: string; // 职位
gender: string; // 性别
level: string; // 职级
skills: string[]; // 技能标签
joinDate: Date; // 入职日期
createdAt: Date;
}
显示字段:
操作路径:
侧边栏包含两个标签页:
1. 基本信息标签页:
2. 项目负载标签页:
查看员工任务:
数据来源:
// 查询员工负责的项目
const projects = await Parse.Query('Project')
.equalTo('assignee', employeeId)
.equalTo('status', '进行中')
.find();
// 或从 ProjectTeam 表查询
const teams = await Parse.Query('ProjectTeam')
.equalTo('profile', employeeId)
.include('project')
.find();
可编辑字段:
不可编辑字段:
操作路径:
保存逻辑:
await EmployeeService.updateEmployee(employeeId, {
name: formData.name,
mobile: formData.mobile,
roleName: formData.roleName,
departmentId: formData.departmentId,
isDisabled: formData.isDisabled,
data: {
realname: formData.realname
}
});
操作路径:
isDisabled 字段影响:
/admin/customers)数据来源:ContactInfo 表
数据结构:
{
id: string;
name: string; // 客户姓名
mobile: string; // 手机号
external_userid: string; // 企微外部联系人ID
source: string; // 来源(企微/电话/网站等)
type: string; // 类型(企业成员/外部联系人)
avatar: string; // 头像
createdAt: Date;
data: {
avatar: string;
name: string;
// 其他扩展字段
};
}
显示字段:
操作路径:
详情面板包含:
1. 基本信息卡片:
2. 关联项目:
3. 所在群聊:
4. 跟进记录:
ActivityLog 表)数据查询逻辑:
// 查询客户项目
const projects = await Parse.Query('Project')
.equalTo('contact', customerId)
.include('assignee')
.find();
// 查询客户群聊
const groupContacts = await Parse.Query('GroupChatContact')
.equalTo('userid', customer.get('external_userid'))
.include('groupChat')
.include('groupChat.project')
.find();
// 查询跟进记录
const followUps = await Parse.Query('ActivityLog')
.equalTo('entityId', customerId)
.equalTo('module', 'customer')
.include('actor')
.descending('createdAt')
.find();
/admin/groupchats)数据来源:GroupChat 表
数据结构:
{
id: string;
chat_id: string; // 企微群ID
name: string; // 群名称
project: Pointer; // 关联项目
memberCount: number; // 成员数量
isDisabled: boolean; // 是否禁用
member_list: Array<{ // 成员列表
userid: string;
type: number; // 1=企业成员, 2=外部联系人
join_time: number;
}>;
createdAt: Date;
}
显示字段:
统计维度:
筛选条件:
操作路径:
关联现有项目:
const groupChat = await Parse.Query('GroupChat').get(groupChatId);
groupChat.set('project', project.toPointer());
await groupChat.save();
// 创建 ProjectGroup 关联(支持多项目多群)
const projectGroup = new ProjectGroup();
projectGroup.set('project', project.toPointer());
projectGroup.set('groupChat', groupChat.toPointer());
projectGroup.set('isPrimary', true);
await projectGroup.save();
创建新项目:
// 1. 创建项目
const project = new Project();
project.set('title', projectName);
project.set('company', company.toPointer());
project.set('status', '待分配');
project.set('currentStage', '订单分配');
project.set('data', {
createdBy: 'admin',
createdFrom: 'admin_groupchat',
groupChatId: groupChatId
});
await project.save();
// 2. 关联群聊
groupChat.set('project', project.toPointer());
await groupChat.save();
// 3. 创建 ProjectGroup
const projectGroup = new ProjectGroup();
projectGroup.set('project', project.toPointer());
projectGroup.set('groupChat', groupChat.toPointer());
projectGroup.set('isPrimary', true);
await projectGroup.save();
操作路径:
详情内容:
数据来源:
// 从企微API获取群聊详情
const chatInfo = await WxworkCorp.externalContact.groupChat.get(chat_id);
可修改字段:
操作路径:
{
objectId: string;
title: string; // 项目名称
company: Pointer<Company>;
contact: Pointer<ContactInfo>; // 客户
assignee: Pointer<Profile>; // 负责人
department: Pointer<Department>; // 项目组
status: string; // 状态(待分配/进行中/已完成/已取消)
currentStage: string; // 当前阶段
deadline: Date; // 截止时间
createdAt: Date;
updatedAt: Date;
isDeleted: boolean;
data: {
// 订单分配阶段
orderApproval: object; // 订单审批信息
quotation: object; // 报价信息
// 需求确认阶段
requirements: object; // 需求信息
aiAnalysis: object; // AI分析结果
// 交付执行阶段
deliveryApproval: object; // 交付审批信息
deliveryStageStatus: object; // 各阶段状态
spaceConfirmations: object; // 空间确认记录
// 售后归档阶段
payments: array; // 支付记录
totalAmount: number; // 总金额
paidAmount: number; // 已付金额
// 其他
assignedDesigners: string[]; // 分配的设计师
crossTeamCollaborators: string[]; // 跨组协作者
primaryTeamId: string; // 主要团队ID
};
}
{
objectId: string;
name: string; // 昵称
mobile: string;
userid: string; // 企微ID
roleName: string; // 身份
department: Pointer<Department>;
company: Pointer<Company>;
isDeleted: boolean;
createdAt: Date;
data: {
realname: string; // 真实姓名
avatar: string;
email: string;
position: string;
gender: string;
level: string;
skills: string[];
};
}
{
objectId: string;
name: string;
mobile: string;
external_userid: string; // 企微外部联系人ID
source: string; // 来源
company: Pointer<Company>;
isDeleted: boolean;
createdAt: Date;
data: {
avatar: string;
name: string;
type: string;
};
}
{
objectId: string;
name: string;
leader: Pointer<Profile>;
type: string; // 'project'
company: Pointer<Company>;
isDeleted: boolean;
createdAt: Date;
data: object;
}
{
objectId: string;
chat_id: string; // 企微群ID
name: string;
project: Pointer<Project>;
company: Pointer<Company>;
isDisabled: boolean;
member_list: array;
createdAt: Date;
}
{
objectId: string;
name: string;
projectId: string;
projectName: string;
designer: string;
designerId: string;
team: string;
teamId: string;
coverImage: string;
images: string[];
area: number;
projectType: string;
spaceType: string;
renderingLevel: string;
tag: string[];
totalPrice: number;
completionDate: Date;
viewCount: number;
shareCount: number;
favoriteCount: number;
isExcellent: boolean;
isPublished: boolean;
company: Pointer<Company>;
isDeleted: boolean;
createdAt: Date;
}
{
objectId: string;
title: string;
description: string;
status: string; // 待处理/处理中/已解决/已关闭
priority: string; // 紧急/高/中/低
project: Pointer<Project>;
creator: Pointer<Profile>;
assignee: Pointer<Profile>;
company: Pointer<Company>;
isDeleted: boolean;
createdAt: Date;
updatedAt: Date;
}
{
objectId: string;
fileName: string;
fileUrl: string;
fileSize: number;
fileType: string;
category: string;
project: Pointer<Project>;
product: Pointer<Product>; // 空间
stage: string; // 阶段
uploadedBy: Pointer<Profile>;
uploadedAt: Date;
analysisResult: object; // AI分析结果
approvalStatus: string; // 审批状态
company: Pointer<Company>;
isDeleted: boolean;
}
客服工作台首页
├── 查看项目总数 → 跳转项目列表(全部)
├── 查看待分配项目 → 跳转项目列表(筛选待分配)
├── 待跟进尾款项目
│ └── 点击"开始跟进" → 跳转项目详情(售后归档阶段)
├── 紧急事件
│ └── 点击事件卡片 → 跳转对应项目阶段
└── 待办任务
├── 查看详情 → 展开问题详情
├── 添加评论 → 在问题下评论
├── 催办 → 发送催办通知
└── 新建问题 → 创建项目问题
案例库
├── 浏览案例 → 查看案例详情
├── 点击数据统计 → 展开统计面板
│ ├── Top 5 分享案例
│ ├── 客户最喜欢风格
│ └── 设计师推荐率
└── 筛选搜索 → 按条件筛选案例
项目列表
├── 切换视图模式
│ ├── 卡片视图(看板)
│ ├── 列表视图
│ └── 监控大盘
├── 点击项目卡片 → 跳转项目详情
└── 筛选排序 → 按条件筛选项目
需求确认阶段
├── 拖拽参考图片 → AI自动分析归类
├── 填写需求信息
│ ├── 全局需求
│ └── 空间需求
├── 点击AI生成方案 → 生成设计方案
├── 展开设计助手 → AI聊天助手
└── 确认需求 → 进入下一阶段
交付执行阶段
├── 拖拽交付图片 → 弹出AI分析弹窗
├── AI自动识别阶段 → 显示分析结果
├── 确认交付清单 → 文件归类到各阶段
└── 上传交付清单 → 提交审批
售后归档阶段
├── 上传支付凭证 → AI提取金额
├── 预览支付凭证 → 放大查看
└── 查看尾款详情 → 显示支付记录
管理员后台总览
├── 点击统计卡片 → 展开明细面板
│ ├── 总项目数 → 项目明细
│ ├── 进行中项目 → 进行中项目明细
│ ├── 已完成项目 → 已完成项目明细
│ ├── 设计师总数 → 设计师明细
│ ├── 客户总数 → 客户明细
│ └── 总收入 → 收入明细
└── 查看图表 → 项目趋势图、收入趋势图
项目管理
├── 查看项目列表 → 表格展示
├── 右键预览详情 → 弹出详情面板
├── 分配设计师 → 打开分配弹窗
│ ├── 选择主要负责人
│ ├── 选择协作成员
│ └── 保存分配
├── 筛选排序 → 按条件筛选
└── 跳转项目详情 → 查看完整信息
项目组管理
├── 查看项目组列表
├── 新建项目组
│ ├── 填写名称
│ ├── 选择组长
│ └── 保存
├── 编辑项目组
│ ├── 修改名称
│ ├── 更换组长
│ └── 保存
├── 删除项目组 → 软删除
└── 查看成员 → 展开成员列表
员工管理
├── 查看员工列表
├── 查看详情 → 打开员工信息侧边栏
│ ├── 基本信息标签页
│ └── 项目负载标签页
├── 查看任务安排 → 显示负责的项目
├── 编辑信息
│ ├── 修改可编辑字段
│ └── 保存
└── 禁用/启用员工 → 更新状态
客户管理
├── 查看客户列表
├── 点击客户 → 打开详情面板
│ ├── 基本信息
│ ├── 关联项目
│ ├── 所在群聊
│ └── 跟进记录
└── 筛选搜索 → 按条件筛选
群组管理
├── 查看群组列表
├── 统计企微群聊 → 显示统计数据
├── 关联项目
│ ├── 关联现有项目
│ └── 创建新项目
├── 查看群聊详情 → 打开详情面板
│ ├── 群信息
│ ├── 成员列表
│ └── 关联项目
└── 修改群聊信息 → 编辑保存
项目统计:
时间分析:
客户分析:
工作量统计:
绩效分析:
能力评估:
案例统计:
热门分析:
设计师分析:
收入统计:
回款分析:
项目金额分布:
问题统计:
问题分析:
本文档详细梳理了客服板块和管理员板块的所有功能模块、操作流程、数据字段和计算逻辑。主要特点:
本文档可作为产品复盘、功能优化、培训教材的重要参考资料。
| 功能模块 | 客服 | 组长 | 设计师 | 管理员 |
|---|---|---|---|---|
| 工作台首页 | ✅ | ✅ | ✅ | ✅ |
| 项目列表 | ✅ | ✅ | ✅ | ✅ |
| 案例库 | ✅ | ✅ | ✅ | ✅ |
| 订单分配 | ✅ | ✅审批 | ❌ | ✅ |
| 需求确认 | ✅ | ✅ | ✅ | ✅ |
| 交付执行 | ✅ | ✅审批 | ✅ | ✅ |
| 售后归档 | ✅ | ✅ | ✅ | ✅ |
| 项目管理 | ❌ | ❌ | ❌ | ✅ |
| 项目组管理 | ❌ | ❌ | ❌ | ✅ |
| 员工管理 | ❌ | ❌ | ❌ | ✅ |
| 客户管理 | ❌ | ❌ | ❌ | ✅ |
| 群组管理 | ❌ | ❌ | ❌ | ✅ |
| 分配设计师 | ❌ | ✅ | ❌ | ✅ |
| 审批订单 | ❌ | ✅ | ❌ | ✅ |
| 审批交付 | ❌ | ✅ | ❌ | ✅ |
客服:
组长:
设计师:
管理员:
graph TD
A[客服登录系统] --> B[查看工作台首页]
B --> C{选择工作内容}
C -->|处理新咨询| D[创建新项目]
D --> E[填写客户信息]
E --> F[填写项目基本信息]
F --> G[提交订单分配]
G --> H[等待组长审批]
C -->|跟进尾款| I[查看待跟进尾款列表]
I --> J[点击开始跟进]
J --> K[进入售后归档阶段]
K --> L[查看尾款详情]
L --> M[联系客户催款]
C -->|处理紧急事件| N[查看紧急事件列表]
N --> O[点击紧急事件]
O --> P[进入对应项目阶段]
P --> Q[处理紧急事项]
C -->|处理待办任务| R[查看待办任务列表]
R --> S[点击任务详情]
S --> T{任务类型}
T -->|添加评论| U[输入评论内容]
T -->|催办| V[发送催办通知]
T -->|新建问题| W[创建项目问题]
H --> X{审批结果}
X -->|通过| Y[进入需求确认阶段]
X -->|驳回| Z[修改订单信息]
Z --> G
Y --> AA[填写需求信息]
AA --> AB[拖拽参考图片]
AB --> AC[AI自动分析]
AC --> AD[点击AI生成方案]
AD --> AE[确认需求]
AE --> AF[进入交付执行阶段]
graph TD
A[管理员登录系统] --> B[查看总览看板]
B --> C[查看统计数据]
C --> D{选择管理内容}
D -->|项目管理| E[进入项目管理页面]
E --> F[查看项目列表]
F --> G{项目操作}
G -->|预览详情| H[打开详情面板]
G -->|分配设计师| I[打开分配弹窗]
I --> J[选择主要负责人]
J --> K[选择协作成员]
K --> L[保存分配]
L --> M[更新项目信息]
D -->|项目组管理| N[进入项目组管理]
N --> O{项目组操作}
O -->|新建| P[填写项目组信息]
P --> Q[选择组长]
Q --> R[保存项目组]
O -->|编辑| S[修改项目组信息]
S --> T[保存修改]
O -->|删除| U[确认删除]
U --> V[软删除项目组]
D -->|员工管理| W[进入员工管理]
W --> X{员工操作}
X -->|查看详情| Y[打开员工信息面板]
Y --> Z[查看基本信息]
Y --> AA[查看项目负载]
X -->|编辑信息| AB[修改员工信息]
AB --> AC[保存修改]
X -->|禁用/启用| AD[更新员工状态]
D -->|客户管理| AE[进入客户管理]
AE --> AF[查看客户列表]
AF --> AG[点击客户]
AG --> AH[查看客户详情]
AH --> AI[查看关联项目]
AH --> AJ[查看所在群聊]
AH --> AK[查看跟进记录]
D -->|群组管理| AL[进入群组管理]
AL --> AM[查看群组列表]
AM --> AN{群组操作}
AN -->|关联项目| AO[选择现有项目]
AN -->|创建项目| AP[填写项目信息]
AP --> AQ[保存新项目]
AQ --> AR[关联群聊]
AN -->|查看详情| AS[打开群聊详情]
AS --> AT[查看成员列表]
graph LR
A[订单分配] --> B{组长审批}
B -->|通过| C[确认需求]
B -->|驳回| A
C --> D[填写需求]
D --> E[AI生成方案]
E --> F[确认需求]
F --> G[交付执行]
G --> H[白模阶段]
H --> I[软装阶段]
I --> J[渲染阶段]
J --> K[后期阶段]
K --> L[上传交付清单]
L --> M{组长审批}
M -->|通过| N[售后归档]
M -->|驳回| G
N --> O[上传支付凭证]
O --> P[确认尾款]
P --> Q[项目完成]
客服创建项目
↓
Project表(status: 待分配, currentStage: 订单分配)
↓
组长审批
↓
Project.data.orderApproval(status: approved)
↓
自动更新 Project(status: 进行中, currentStage: 确认需求)
↓
客服填写需求
↓
Project.data.requirements
↓
AI生成方案
↓
Project.data.aiAnalysis
↓
确认需求
↓
Project(currentStage: 交付执行)
↓
设计师上传文件
↓
ProjectFile表(stage: white_model/soft_decor/rendering/post_process)
↓
AI分析文件
↓
ProjectFile.analysisResult
↓
客服确认空间
↓
Project.data.spaceConfirmations
↓
上传交付清单
↓
Project.data.deliveryApproval(status: pending)
↓
组长审批
↓
Project.data.deliveryApproval(status: approved)
↓
自动更新 Project(currentStage: 售后归档)
↓
客服上传支付凭证
↓
Project.data.payments
↓
AI提取金额
↓
更新 Project.data.paidAmount
↓
确认尾款
↓
Project(status: 已完成)
↓
自动生成案例
↓
Case表(isPublished: false)
管理员/组长分配设计师
↓
选择主要负责人
↓
Project.assignee = Pointer<Profile>
↓
选择协作成员
↓
Project.data.assignedDesigners = [id1, id2, ...]
↓
创建 ProjectTeam 记录
↓
ProjectTeam(project, profile, role: primary/collaborator)
↓
设计师可见项目
↓
设计师工作台显示项目
管理员查看群组列表
↓
选择未关联项目的群聊
↓
创建新项目 或 关联现有项目
↓
Project表(新建或更新)
↓
GroupChat.project = Pointer<Project>
↓
创建 ProjectGroup 记录
↓
ProjectGroup(project, groupChat, isPrimary: true)
↓
群聊成员可见项目
↓
企微群聊中显示项目卡片
服务:ImageAnalysisService
模型:豆包1.6 (fmode-1.6-cn)
分析流程:
1. 接收图片文件
2. 转换为Base64编码
3. 调用豆包API
4. 解析返回结果
5. 提取关键信息:
- 图片质量(清晰度、亮度、对比度)
- 内容识别(类别、置信度、描述、标签)
- 技术参数(格式、色彩空间、DPI、分辨率)
- 阶段分类建议(white_model/soft_decor/rendering/post_process)
6. 返回分析结果
应用场景:
核心函数:getProjectStatusByStage()
判断逻辑:
function getProjectStatusByStage(stageId: string, currentStatus?: string): string {
// 如果已经是完成或取消状态,保持不变
if (currentStatus === '已完成' || currentStatus === '已取消') {
return currentStatus;
}
const corePhase = mapStageToCorePhase(stageId);
switch (corePhase) {
case 'order':
return '待分配';
case 'requirements':
case 'delivery':
return '进行中';
case 'aftercare':
return '已完成';
default:
return '待分配';
}
}
应用场景:
技术:HTML5 Drag and Drop API
实现步骤:
1. 监听 dragover 事件
- event.preventDefault()
- event.dataTransfer.dropEffect = 'move'
- 显示拖拽提示
2. 监听 dragleave 事件
- 隐藏拖拽提示
3. 监听 drop 事件
- event.preventDefault()
- 获取文件列表:event.dataTransfer.files
- 过滤文件类型(只允许图片)
- 打开上传弹窗
4. 自动触发AI分析
- 延迟500ms
- 遍历文件列表
- 调用 ImageAnalysisService.analyzeImage()
- 显示分析结果
5. 确认上传
- 批量上传文件到服务器
- 保存文件记录到 ProjectFile 表
- 更新项目数据
数据结构:
// 订单审批
Project.data.orderApproval = {
status: 'pending' | 'approved' | 'rejected';
submittedAt: Date;
submittedBy: string;
submittedByName: string;
approvedAt?: Date;
approvedBy?: string;
approvedByName?: string;
rejectedAt?: Date;
rejectedBy?: string;
rejectedByName?: string;
rejectionReason?: string;
};
// 交付审批
Project.data.deliveryApproval = {
status: 'pending' | 'approved' | 'rejected';
stage: 'delivery';
totalFiles: number;
types: {
white_model: number;
soft_decor: number;
rendering: number;
post_process: number;
};
submittedAt: Date;
submittedByName: string;
submittedById: string;
approvedAt?: Date;
approvedBy?: string;
approvedByName?: string;
rejectedAt?: Date;
rejectedBy?: string;
rejectedByName?: string;
rejectionReason?: string;
};
审批流程:
1. 提交审批
- 设置 status = 'pending'
- 记录提交人和时间
- 通知组长
2. 组长审批
- 查看审批详情
- 选择通过或驳回
- 填写驳回原因(如驳回)
- 保存审批结果
3. 审批通过
- 设置 status = 'approved'
- 记录审批人和时间
- 自动更新项目阶段
- 通知提交人
4. 审批驳回
- 设置 status = 'rejected'
- 记录驳回人、时间和原因
- 通知提交人
- 项目回退到上一阶段
问题:项目负责人显示不一致
原因:
Project.assignee 字段为空ProjectTeam 表中有主要负责人记录解决方案:
// 优先从 assignee 获取,其次从 ProjectTeam 获取
let assigneeName = project.get('assignee')?.get('name');
if (!assigneeName || assigneeName === '未分配') {
const primaryDesigner = await getPrimaryDesignerFromProjectTeam(projectId);
if (primaryDesigner) {
assigneeName = primaryDesigner.name;
}
}
问题:项目状态与实际阶段不符
原因:
status 字段未更新解决方案:
// 使用自动判断函数,而不是直接读取 status 字段
const autoStatus = getProjectStatusByStage(currentStage, status);
问题:拖拽上传后文件未保存
原因:
解决方案:
// 1. 检查文件大小
if (file.size > 10 * 1024 * 1024) {
alert('文件大小不能超过10MB');
return;
}
// 2. 添加重试机制
async function uploadWithRetry(file, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await uploadFile(file);
} catch (error) {
if (i === maxRetries - 1) throw error;
await sleep(1000 * (i + 1));
}
}
}
// 3. 检查权限
const currentUser = Parse.User.current();
if (!currentUser) {
alert('请先登录');
return;
}
问题:AI分析长时间无响应
原因:
解决方案:
// 1. 压缩图片
async function compressImage(file) {
if (file.size > 2 * 1024 * 1024) {
// 压缩到2MB以下
return await imageCompression(file, {
maxSizeMB: 2,
maxWidthOrHeight: 1920
});
}
return file;
}
// 2. 设置超时
const analysisPromise = ImageAnalysisService.analyzeImage(file);
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error('分析超时')), 30000)
);
const result = await Promise.race([analysisPromise, timeoutPromise]);
// 3. 降级处理
try {
const result = await analyzeImage(file);
} catch (error) {
console.error('AI分析失败,使用默认分类', error);
return {
category: 'unknown',
confidence: 0,
description: '自动分类失败,请手动选择'
};
}
问题:项目列表加载慢
优化方案:
// 1. 使用分页
query.limit(20);
query.skip(page * 20);
// 2. 只查询必要字段
query.select('title', 'status', 'currentStage', 'deadline', 'updatedAt');
// 3. 使用索引
// 在Parse Server后台为常用查询字段创建索引
// - status
// - currentStage
// - company
// - assignee
// - createdAt
// - updatedAt
// 4. 缓存查询结果
const cacheKey = `projects_${status}_${page}`;
let projects = cache.get(cacheKey);
if (!projects) {
projects = await query.find();
cache.set(cacheKey, projects, 60); // 缓存60秒
}
优化方案:
// 1. 并发上传(限制并发数)
async function uploadFiles(files) {
const concurrency = 3;
const results = [];
for (let i = 0; i < files.length; i += concurrency) {
const batch = files.slice(i, i + concurrency);
const batchResults = await Promise.all(
batch.map(file => uploadFile(file))
);
results.push(...batchResults);
}
return results;
}
// 2. 断点续传
async function uploadLargeFile(file) {
const chunkSize = 1024 * 1024; // 1MB
const chunks = Math.ceil(file.size / chunkSize);
for (let i = 0; i < chunks; i++) {
const start = i * chunkSize;
const end = Math.min(start + chunkSize, file.size);
const chunk = file.slice(start, end);
await uploadChunk(chunk, i, chunks);
}
}
// 3. 压缩图片
async function compressAndUpload(file) {
const compressed = await imageCompression(file, {
maxSizeMB: 2,
maxWidthOrHeight: 1920,
useWebWorker: true
});
return await uploadFile(compressed);
}
优化方案:
// 1. 虚拟滚动(大列表)
<cdk-virtual-scroll-viewport itemSize="80" class="project-list">
<div *cdkVirtualFor="let project of projects">
{{ project.title }}
</div>
</cdk-virtual-scroll-viewport>
// 2. 懒加载图片
<img [src]="placeholder" [lazyLoad]="imageUrl" />
// 3. 使用 OnPush 变更检测
@Component({
changeDetection: ChangeDetectionStrategy.OnPush
})
// 4. 使用 trackBy
<div *ngFor="let project of projects; trackBy: trackByProjectId">
{{ project.title }}
</div>
trackByProjectId(index: number, project: Project): string {
return project.id;
}
实现方式:
// 1. 路由守卫
@Injectable()
export class RoleGuard implements CanActivate {
canActivate(route: ActivatedRouteSnapshot): boolean {
const currentUser = Parse.User.current();
const requiredRole = route.data['role'];
const userRole = currentUser?.get('roleName');
return userRole === requiredRole;
}
}
// 2. 数据权限
async function getProjects(userId: string, role: string) {
const query = new Parse.Query('Project');
if (role === '设计师') {
// 设计师只能查看自己负责的项目
query.equalTo('assignee', userId);
} else if (role === '客服' || role === '组长') {
// 客服和组长可以查看所有项目
// 不添加额外筛选
}
return await query.find();
}
// 3. 操作权限
function canEditProject(project: Project, user: User): boolean {
const role = user.get('roleName');
const assigneeId = project.get('assignee')?.id;
if (role === '管理员' || role === '组长') {
return true;
}
if (role === '客服') {
const createdBy = project.get('data')?.createdBy;
return createdBy === user.id;
}
if (role === '设计师') {
return assigneeId === user.id;
}
return false;
}
实现方式:
// 1. 前端验证
function validateProjectData(data: any): string[] {
const errors: string[] = [];
if (!data.title || data.title.trim().length === 0) {
errors.push('项目名称不能为空');
}
if (!data.customerId) {
errors.push('请选择客户');
}
if (data.deadline && new Date(data.deadline) < new Date()) {
errors.push('截止时间不能早于当前时间');
}
return errors;
}
// 2. 后端验证(Parse Cloud Code)
Parse.Cloud.beforeSave('Project', async (request) => {
const project = request.object;
// 验证必填字段
if (!project.get('title')) {
throw new Parse.Error(400, '项目名称不能为空');
}
// 验证数据格式
const deadline = project.get('deadline');
if (deadline && !(deadline instanceof Date)) {
throw new Parse.Error(400, '截止时间格式错误');
}
// 验证权限
const user = request.user;
if (!user) {
throw new Parse.Error(401, '未登录');
}
const role = user.get('roleName');
if (!['客服', '组长', '管理员'].includes(role)) {
throw new Parse.Error(403, '无权限创建项目');
}
});
实现方式:
// 1. 脱敏显示
function maskPhone(phone: string): string {
if (!phone || phone.length < 11) return phone;
return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
}
function maskIdCard(idCard: string): string {
if (!idCard || idCard.length < 18) return idCard;
return idCard.replace(/(\d{6})\d{8}(\d{4})/, '$1********$2');
}
// 2. 加密存储
async function savePaymentInfo(data: any) {
const encrypted = await encrypt(JSON.stringify(data));
project.set('paymentInfo', encrypted);
await project.save();
}
async function getPaymentInfo(project: Project) {
const encrypted = project.get('paymentInfo');
const decrypted = await decrypt(encrypted);
return JSON.parse(decrypted);
}
// 3. 日志记录
async function logSensitiveOperation(
userId: string,
action: string,
entityId: string,
details: any
) {
const log = new Parse.Object('AuditLog');
log.set('user', userId);
log.set('action', action);
log.set('entityId', entityId);
log.set('details', details);
log.set('timestamp', new Date());
log.set('ip', request.ip);
await log.save();
}
1. 智能推荐
2. 数据分析
3. 自动化流程
4. 移动端支持
1. 性能优化
2. AI能力增强
3. 数据安全
4. 集成能力
详见第三章"数据字段汇总"
详见独立API文档
| 错误码 | 说明 | 解决方案 |
|---|---|---|
| 400 | 请求参数错误 | 检查请求参数格式 |
| 401 | 未登录 | 重新登录 |
| 403 | 无权限 | 联系管理员分配权限 |
| 404 | 资源不存在 | 检查资源ID是否正确 |
| 500 | 服务器错误 | 联系技术支持 |
v1.0.0 (2025-01-15)
v1.1.0 (2025-02-01)
v1.2.0 (2025-03-01)
文档版本:v1.0 最后更新:2025-01-15 维护人员:产品团队 联系方式:product@example.com