2024-10-24
完成客服板块项目列表页面(/customer-service/project-list)的真实Parse Server数据对接,并按照订单分配、确认需求、交付执行、售后四个阶段正确显示项目。
修改前:
columns = [
{ id: 'pending', name: '待分配' },
{ id: 'req', name: '需求深化' },
{ id: 'delivery', name: '交付中' },
{ id: 'done', name: '已完成' }
]
修改后:
columns = [
{ id: 'order', name: '订单分配' },
{ id: 'requirements', name: '确认需求' },
{ id: 'delivery', name: '交付执行' },
{ id: 'aftercare', name: '售后' }
]
statusOptions = [
{ value: 'all', label: '全部' },
{ value: 'order', label: '订单分配' },
{ value: 'requirements', label: '确认需求' },
{ value: 'delivery', label: '交付执行' },
{ value: 'aftercare', label: '售后' }
]
查询代码:
async loadProjects(): Promise<void> {
const ProjectQuery = new Parse.Query('Project');
ProjectQuery.equalTo('company', this.getCompanyPointer());
ProjectQuery.equalTo('isDeleted', false);
ProjectQuery.include('contact', 'assignee', 'owner');
ProjectQuery.descending('updatedAt');
ProjectQuery.limit(500);
const projectObjects = await ProjectQuery.find();
// 转换为前端格式
const projects: Project[] = projectObjects.map((obj: FmodeObject) => {
const contact = obj.get('contact');
const assignee = obj.get('assignee');
const mappedStage = this.mapStage(obj.get('currentStage'));
return {
id: obj.id,
name: obj.get('title') || '未命名项目',
customerName: contact?.get('name') || '未知客户',
status: this.mapStatus(obj.get('status')),
currentStage: mappedStage,
assigneeName: assignee?.get('name') || '未分配',
deadline: obj.get('deadline') || new Date(),
// ... 其他字段
};
});
}
关键字段:
company: 公司指针(多租户隔离)isDeleted: 软删除标记contact: 客户信息(Pointer → ContactInfo)assignee: 负责设计师(Pointer → Profile)status: 项目状态(进行中/已完成/已暂停/已延期)currentStage: 当前阶段(订单分配/需求沟通/建模/软装/渲染等)deadline: 截止时间mapStage方法:
private mapStage(parseStage: string): ProjectStage {
// 直接返回Parse Server的阶段,不做转换
// Parse Server的currentStage字段包含:
// 订单分配、需求沟通、建模、软装、渲染、后期、尾款结算、投诉处理等
if (!parseStage) {
return '需求沟通'; // 默认阶段
}
return parseStage as ProjectStage;
}
支持的阶段:
mapStatus方法:
private mapStatus(parseStatus: string): ProjectStatus {
const statusMap: Record<string, ProjectStatus> = {
'进行中': '进行中',
'已完成': '已完成',
'已暂停': '已暂停',
'已延期': '已延期'
};
return statusMap[parseStatus] || '进行中';
}
判断条件:
private isOrderAssignment(p: Project): boolean {
// 未分配设计师 或 currentStage为"订单分配"
return !p.assigneeId || p.assigneeId.trim() === '' || p.currentStage === '订单分配';
}
包含项目:
判断条件:
private isRequirementsConfirmation(p: Project): boolean {
const requirementStages: ProjectStage[] = ['需求沟通', '方案确认'];
return !this.isAftercare(p) && !this.isOrderAssignment(p) &&
requirementStages.includes(p.currentStage);
}
包含阶段:
判断条件:
private isDeliveryExecution(p: Project): boolean {
const deliveryStages: ProjectStage[] = ['建模', '软装', '渲染', '后期', '尾款结算'];
return !this.isAftercare(p) && !this.isOrderAssignment(p) &&
deliveryStages.includes(p.currentStage);
}
包含阶段:
判断条件:
private isAftercare(p: Project): boolean {
const aftercareStages: ProjectStage[] = ['投诉处理', '客户评价'];
return p.status === '已完成' || aftercareStages.includes(p.currentStage);
}
包含情况:
修改后:
getProjectsByColumn(columnId: 'order' | 'requirements' | 'delivery' | 'aftercare'): ProjectListItem[] {
const list = this.projects();
switch (columnId) {
case 'order':
return list.filter(p => this.isOrderAssignment(p));
case 'requirements':
return list.filter(p => this.isRequirementsConfirmation(p));
case 'delivery':
return list.filter(p => this.isDeliveryExecution(p));
case 'aftercare':
return list.filter(p => this.isAftercare(p));
}
}
修改后:
getColumnIdForProject(project: ProjectListItem): 'order' | 'requirements' | 'delivery' | 'aftercare' {
if (this.isOrderAssignment(project)) return 'order';
if (this.isRequirementsConfirmation(project)) return 'requirements';
if (this.isDeliveryExecution(project)) return 'delivery';
if (this.isAftercare(project)) return 'aftercare';
return 'requirements'; // 默认为确认需求阶段
}
修改后:
navigateToProject(project: ProjectListItem, columnId: 'order' | 'requirements' | 'delivery' | 'aftercare') {
const stageMapping = {
'order': '订单分配',
'requirements': project.currentStage || '需求沟通',
'delivery': project.currentStage || '建模',
'aftercare': '客户评价'
};
this.router.navigate(['/designer/project-detail', project.id], {
queryParams: {
role: 'customer-service',
activeTab: 'progress',
currentStage: stageMapping[columnId]
}
});
}
修改前:
@if (col.id === 'pending') {
<span class="pending-badge">待分配</span>
}
修改后:
@if (col.id === 'order') {
<span class="pending-badge">待分配</span>
}
Parse Server (Project表)
↓
loadProjects() 查询
↓
mapStage() / mapStatus() 映射
↓
processProjects() 处理
↓
applyFiltersAndSorting() 筛选排序
↓
getProjectsByColumn() 按列分组
↓
HTML模板渲染
↓
四个看板列显示:
- 订单分配 (order)
- 确认需求 (requirements)
- 交付执行 (delivery)
- 售后 (aftercare)
| Parse Server currentStage | 看板列 | 列ID |
|---|---|---|
| 订单分配 | 订单分配 | order |
| 需求沟通 | 确认需求 | requirements |
| 方案确认 | 确认需求 | requirements |
| 建模 | 交付执行 | delivery |
| 软装 | 交付执行 | delivery |
| 渲染 | 交付执行 | delivery |
| 后期 | 交付执行 | delivery |
| 尾款结算 | 交付执行 | delivery |
| 投诉处理 | 售后 | aftercare |
| 客户评价 | 售后 | aftercare |
| status=已完成 | 售后 | aftercare |
yss-project/src/app/pages/customer-service/project-list/project-list.ts
yss-project/src/app/pages/customer-service/project-list/project-list.html
真实数据对接
四阶段看板
数据映射
筛选排序
视图模式
✅ 无TypeScript错误 ✅ 无Linter警告 ✅ 类型检查通过 ✅ 项目可正常运行
http://localhost:4200/customer-service/project-list
| 字段名 | 类型 | 说明 | 示例值 |
|---|---|---|---|
| objectId | String | 项目ID | "abc123" |
| title | String | 项目名称 | "李总别墅设计" |
| company | Pointer | 所属公司 | → Company |
| contact | Pointer | 客户信息 | → ContactInfo |
| assignee | Pointer | 负责设计师 | → Profile |
| owner | Pointer | 创建人 | → Profile |
| status | String | 项目状态 | "进行中" |
| currentStage | String | 当前阶段 | "建模" |
| deadline | Date | 截止时间 | 2024-12-31 |
| description | String | 项目描述 | "..." |
| priority | String | 优先级 | "high" |
| isDeleted | Boolean | 软删除 | false |
| createdAt | Date | 创建时间 | 2024-01-01 |
| updatedAt | Date | 更新时间 | 2024-10-24 |
本次更新成功完成了客服项目列表的真实数据对接,实现了以下核心目标:
✅ 真实数据显示 - 从Parse Server加载真实项目数据
✅ 四阶段看板 - 按订单分配、确认需求、交付执行、售后分组
✅ 正确映射 - Parse Server字段正确映射到前端模型
✅ 完整功能 - 筛选、排序、搜索、跳转等功能完整
✅ 类型安全 - TypeScript类型检查通过,无编译错误
项目列表现在可以正确显示后端的真实项目数据,并按照业务流程的四个阶段进行组织展示,为客服人员提供了清晰的项目管理视图。
项目现已可以正常编译和运行 ✅