日期: 2025-10-22 16:00
任务: 为组长端接入真实数据库,实现增删查改功能
状态: ✅ 已完成
根据项目规则文档(.trae/rules/project_rules.md)和数据库文档(docs/Database/database-tables-overview.md),为组长端实现完整的数据库接入,使组长端能够:
fmode-ng/parse (FmodeParse)company 字段隔离isDeleted 字段创建了3个核心数据服务:
src/app/pages/team-leader/services/
├── project-data.service.ts # 项目数据服务(增删查改)
├── dashboard-data.service.ts # 仪表盘数据服务(统计)
└── designer.service.ts # 设计师服务(已完善)
| 服务 | 职责 | 主要方法 |
|---|---|---|
| ProjectDataService | 项目增删查改 | getProjects, createProject, updateProject, deleteProject, assignProject |
| DashboardDataService | 统计数据 | getKPIStats, getStageDistribution, getDesignerWorkloadDistribution, getTodoTasks |
| DesignerService | 设计师管理 | getDesigners, getDesignerWorkload, updateDesignerTags, getRecommendedDesigners |
constructor() {
this.cid = localStorage.getItem('company') || '';
console.log('🏢 ProjectDataService初始化,当前公司ID:', this.cid);
this.initParse();
}
private async initParse(): Promise<void> {
const { FmodeParse } = await import('fmode-ng/parse');
this.Parse = FmodeParse.with("nova");
}
关键点:
localStorage.getItem('company') 获取公司IDFmodeParse.with("nova") 初始化Parse连接async getProjects(filters?: {
status?: string;
assignee?: string;
currentStage?: string;
searchTerm?: string;
}): Promise<any[]>
功能:
示例:
// 获取所有进行中的项目
const projects = await projectDataService.getProjects({
status: '进行中'
});
// 获取某个设计师的项目
const designerProjects = await projectDataService.getProjects({
assignee: 'designerId123'
});
// 搜索项目
const searchResults = await projectDataService.getProjects({
searchTerm: '现代简约'
});
async getProjectById(projectId: string): Promise<any>
功能:
async getProjectsByDesigner(designerId: string): Promise<any[]>
功能:
async getOverdueProjects(): Promise<any[]>
功能:
async getDueSoonProjects(): Promise<any[]>
功能:
async createProject(projectData: {
title: string;
customer: string; // ContactInfo ID
assignee?: string; // Profile ID
status?: string;
currentStage?: string;
deadline?: Date;
data?: any;
}): Promise<any>
功能:
示例:
const newProject = await projectDataService.createProject({
title: '李总现代简约全案',
customer: 'contactId123',
assignee: 'designerId456',
status: '进行中',
currentStage: '方案深化',
deadline: new Date('2024-12-31'),
data: {
totalBudget: 120000,
tags: ['全案设计', '现代简约']
}
});
async updateProject(projectId: string, updates: {
title?: string;
status?: string;
currentStage?: string;
assignee?: string;
deadline?: Date;
data?: any;
}): Promise<boolean>
功能:
示例:
// 更新项目状态
await projectDataService.updateProject('projectId123', {
status: '已完成',
currentStage: '售后归档'
});
// 延长截止时间
await projectDataService.updateProject('projectId123', {
deadline: new Date('2025-01-15')
});
async assignProject(projectId: string, designerId: string): Promise<boolean>
功能:
示例:
await projectDataService.assignProject('projectId123', 'designerId456');
async updateProjectStage(projectId: string, stage: string): Promise<boolean>
功能:
async deleteProject(projectId: string): Promise<boolean>
功能:
isDeleted = true)示例:
await projectDataService.deleteProject('projectId123');
async destroyProject(projectId: string): Promise<boolean>
功能:
async getProjectStats(): Promise<{
total: number;
inProgress: number;
completed: number;
overdue: number;
dueSoon: number;
unassigned: number;
}>
功能:
async getKPIStats(): Promise<{
totalProjects: number;
inProgressProjects: number;
completedProjects: number;
overdueProjects: number;
dueSoonProjects: number;
totalDesigners: number;
availableDesigners: number;
busyDesigners: number;
overloadedDesigners: number;
}>
功能:
使用示例:
const kpi = await dashboardDataService.getKPIStats();
console.log(`总项目数: ${kpi.totalProjects}`);
console.log(`超期项目: ${kpi.overdueProjects}`);
console.log(`空闲设计师: ${kpi.availableDesigners}`);
async getStageDistribution(): Promise<Record<string, number>>
功能:
{ '订单分配': 5, '方案深化': 10, ... }async getDesignerWorkloadDistribution(): Promise<{
idle: number;
busy: number;
overload: number;
}>
功能:
async getTodoTasks(): Promise<any[]>
功能:
返回数据结构:
{
id: string; // 任务ID
title: string; // 任务标题
description: string; // 任务描述
deadline: Date; // 截止时间
priority: 'high' | 'medium' | 'low'; // 优先级
type: 'assign' | 'review' | 'performance'; // 任务类型
targetId: string; // 关联项目ID
}
async getDesigners(): Promise<any[]>
功能:
返回数据结构:
{
id: string;
name: string;
mobile: string;
department: string;
departmentId: string;
tags: DesignerTags; // 设计师画像
data: any;
profile: ParseObject;
}
async updateDesignerTags(designerId: string, tags: Partial<DesignerTags>): Promise<boolean>
功能:
示例:
await designerService.updateDesignerTags('designerId123', {
expertise: {
styles: ['现代简约', '北欧风'],
skills: ['建模', '渲染', '后期'],
spaceTypes: ['客厅', '卧室']
},
capacity: {
weeklyProjects: 3,
maxConcurrent: 5,
avgDaysPerProject: 7
}
});
async getDesignerWorkload(designerId: string): Promise<{
projects: any[];
weightedTotal: number;
overdueCount: number;
loadRate: number;
}>
功能:
加权算法:
项目权重 = 类型系数 × 时间系数 × 紧急度系数
类型系数: 硬装=2.0, 软装=1.0
时间系数: 超期=1.5, 临期(≤3天)=1.3, 正常(≤7天)=1.0, 充裕=0.8
紧急度系数: 高=1.2, 中=1.0, 低=0.8
async getRecommendedDesigners(project: any): Promise<any[]>
功能:
评分规则:
总分 = 风格匹配分 × 40% + 负载适配分 × 30% + 历史表现分 × 20% + 紧急加分 × 10%
风格匹配分: 0-100(基于技能、风格、空间类型匹配度)
负载适配分: 0-100(负载率越低分数越高)
历史表现分: 0-100(完成率、评分、按时率)
紧急加分: 0-20(是否接受紧急单)
所有数据服务都提供了 transformProject 等方法,将Parse对象转换为前端友好的格式:
private transformProject(project: any): any {
return {
id: project.id,
name: project.get('title'),
title: project.get('title'),
customerName: customer?.get('name') || '未知客户',
designerName: assignee?.get('name') || '未分配',
status: project.get('status'),
currentStage: project.get('currentStage'),
deadline: project.get('deadline'),
isOverdue: boolean,
overdueDays: number,
dueSoon: boolean,
urgency: 'high' | 'medium' | 'low',
// ... 更多字段
};
}
Parse返回的日期可能是 Date 对象或字符串,统一转换:
const deadline = deadlineRaw instanceof Date
? deadlineRaw
: (deadlineRaw ? new Date(deadlineRaw) : null);
创建Pointer引用:
const Profile = Parse.Object.extend('Profile');
const assignee = new Profile();
assignee.id = designerId;
project.set('assignee', assignee);
import { ProjectDataService } from '../services/project-data.service';
import { DashboardDataService } from '../services/dashboard-data.service';
import { DesignerService } from '../services/designer.service';
export class Dashboard {
constructor(
private projectDataService: ProjectDataService,
private dashboardDataService: DashboardDataService,
private designerService: DesignerService
) {}
}
async ngOnInit() {
// 加载KPI数据
const kpi = await this.dashboardDataService.getKPIStats();
this.totalProjects = kpi.totalProjects;
this.overdueCount = kpi.overdueProjects;
// 加载项目列表
this.projects = await this.projectDataService.getProjects();
// 加载设计师列表
this.designers = await this.designerService.getDesigners();
// 加载待办任务
this.todoTasks = await this.dashboardDataService.getTodoTasks();
}
async onAssignProject(projectId: string, designerId: string) {
const success = await this.projectDataService.assignProject(
projectId,
designerId
);
if (success) {
// 刷新项目列表
this.projects = await this.projectDataService.getProjects();
console.log('✅ 项目分配成功');
}
}
async onUpdateStatus(projectId: string, newStatus: string) {
const success = await this.projectDataService.updateProject(
projectId,
{ status: newStatus }
);
if (success) {
// 刷新列表
this.loadProjects();
}
}
async onSmartRecommend(project: any) {
this.recommendations = await this.designerService.getRecommendedDesigners(
project
);
this.showSmartMatch = true;
}
query.notEqualTo('isDeleted', true);
query.equalTo('company', this.cid);
query.include('customer', 'assignee', 'assignee.department');
query.limit(1000); // 避免一次查询过多数据
优先使用已建立索引的字段进行查询:
company + isDeletedassignee + statuscustomer + isDeletedcurrentStage + statusdeadlineconst Parse = await this.ensureParse();
if (!Parse) {
console.error('❌ Parse未初始化');
return defaultValue;
}
try {
const projects = await query.find();
return projects;
} catch (error) {
console.error('❌ 查询失败:', error);
return [];
}
try {
await project.save();
console.log('✅ 更新成功');
return true;
} catch (error) {
console.error('❌ 更新失败:', error);
return false;
}
确保 localStorage 中有 company 字段:
localStorage.setItem('company', 'your-company-id');
如果数据库为空,可以通过以下方式创建测试数据:
创建公司:
const Company = Parse.Object.extend('Company');
const company = new Company();
company.set('name', '测试公司');
await company.save();
创建部门:
const Department = Parse.Object.extend('Department');
const dept = new Department();
dept.set('name', '设计一组');
dept.set('type', 'project');
dept.set('company', company.toPointer());
await dept.save();
创建设计师:
const Profile = Parse.Object.extend('Profile');
const designer = new Profile();
designer.set('name', '张三');
designer.set('roleName', '组员');
designer.set('company', company.toPointer());
designer.set('department', dept.toPointer());
await designer.save();
创建客户:
const ContactInfo = Parse.Object.extend('ContactInfo');
const contact = new ContactInfo();
contact.set('name', '李总');
contact.set('mobile', '13800138000');
contact.set('company', company.toPointer());
await contact.save();
创建项目:
const project = await projectDataService.createProject({
title: '李总现代简约全案',
customer: contact.id,
assignee: designer.id,
status: '进行中',
currentStage: '方案深化',
deadline: new Date('2024-12-31')
});
| 文件 | 行数 | 说明 |
|---|---|---|
src/app/pages/team-leader/services/project-data.service.ts |
579 | 项目数据服务(增删查改) |
src/app/pages/team-leader/services/dashboard-data.service.ts |
256 | 仪表盘数据服务(统计) |
docs/task/2025102216-team-leader-database-integration.md |
- | 本文档 |
| 文件 | 变更 | 说明 |
|---|---|---|
src/app/pages/team-leader/services/designer.service.ts |
+44行 | 新增 updateDesignerTags 方法,优化 getDesigners 方法 |
A: 检查以下几点:
localStorage.getItem('company') 是否正确isDeleted 是否为 falseA: 在服务中添加详细日志:
console.log('🔍 查询条件:', {
company: this.cid,
status: filters?.status,
assignee: filters?.assignee
});
const projects = await query.find();
console.log('✅ 查询结果:', projects.length, '个项目');
A: 创建Pointer时使用:
const Profile = Parse.Object.extend('Profile');
const pointer = new Profile();
pointer.id = 'profileId';
project.set('assignee', pointer);
读取Pointer时使用 include:
query.include('assignee');
const assignee = project.get('assignee');
console.log(assignee.get('name'));
A: 统一转换为Date对象:
const deadline = project.get('deadline');
const date = deadline instanceof Date
? deadline
: new Date(deadline);
✅ 3个数据服务: ProjectDataService、DashboardDataService、DesignerService
✅ 完整的增删查改: 项目、设计师、统计数据
✅ 智能推荐算法: 基于多维度匹配的设计师推荐
✅ 数据转换层: Parse对象与前端格式的无缝转换
✅ 错误处理: 完善的异常捕获和日志记录
company 字段isDeleted 字段include 减少请求include 关联数据文档版本: v1.0
最后更新: 2025-10-22 16:00
作者: AI Assistant
状态: ✅ 完成