现象:报价组件无法将总报价数据传递给订单分配组件
原因:stage-order.component.ts 缺少接收报价数据的事件处理方法
现象:
❌ 获取项目付款记录失败: Error: This user is not allowed to access non-existent class: ProjectPayment
❌ 计算付款统计失败: Error: This user is not allowed to access non-existent class: ProjectPayment
📋 找到 0 条尾款记录
原因:系统尝试访问不存在的 ProjectPayment 表
stage-order.component.ts添加的方法:
/**
* 处理报价组件的报价数据变化
*/
onQuotationChange(quotation: any): void {
console.log('📊 [订单分配] 报价数据更新:', quotation);
this.quotation = quotation;
this.cdr.markForCheck();
}
/**
* 处理报价组件的总价变化
*/
onTotalChange(total: number): void {
console.log('💰 [订单分配] 总报价更新:', total);
this.quotation.total = total;
this.cdr.markForCheck();
}
/**
* 处理报价组件的加载状态变化
*/
onQuotationLoadingChange(loading: boolean): void {
console.log('⏳ [订单分配] 报价加载状态:', loading);
this.cdr.markForCheck();
}
/**
* 处理报价组件的产品列表变化
*/
onProductsChange(products: any[]): void {
console.log('📦 [订单分配] 产品列表更新:', products.length, '个产品');
this.cdr.markForCheck();
}
HTML模板已正确配置:
<app-quotation-editor
[projectId]="projectId"
[project]="project"
[canEdit]="canEdit"
[viewMode]="'card'"
[currentUser]="currentUser"
(quotationChange)="onQuotationChange($event)"
(totalChange)="onTotalChange($event)"
(loadingChange)="onQuotationLoadingChange($event)"
(productsChange)="onProductsChange($event)">
</app-quotation-editor>
效果:
this.quotation.total 会实时更新aftercare-data.service.ts问题根源:系统设计中不存在 ProjectPayment 表
解决方案:使用 Project.data 字段存储付款数据
getProjectPayments() - 获取所有付款记录async getProjectPayments(projectId: string): Promise<FmodeObject[]> {
console.log(`📊 [降级方案] 从 Project.data.payments 获取付款记录...`);
// 从 Project.data 读取支付记录
const projectQuery = new Parse.Query('Project');
const project = await projectQuery.get(projectId);
const data = project.get('data') || {};
const payments = data.payments || [];
console.log(`✅ 获取项目 ${projectId} 的付款记录,共 ${payments.length} 条(来自Project.data)`);
// 将普通对象转换为类似 Parse.Object 的结构
return payments.map((p: any) => {
const mockParseObject: any = {
id: p.id || p.objectId || '',
get: (key: string) => p[key],
toJSON: () => p,
createdAt: p.createdAt ? new Date(p.createdAt) : new Date(),
updatedAt: p.updatedAt ? new Date(p.updatedAt) : new Date()
};
return mockParseObject;
});
}
getFinalPayments() - 获取尾款记录async getFinalPayments(projectId: string): Promise<FmodeObject[]> {
console.log(`📊 [降级方案] 从 Project.data 获取尾款记录...`);
const projectQuery = new Parse.Query('Project');
const project = await projectQuery.get(projectId);
const data = project.get('data') || {};
// 尝试多个可能的字段名
const finalPayments = data.finalPayments || data.final_payments || [];
const payments = data.payments || [];
// 过滤出尾款类型的付款记录
const finalPaymentRecords = payments.filter((p: any) =>
p.type === 'final' || p.paymentType === 'final'
);
const allFinalPayments = [...finalPayments, ...finalPaymentRecords];
console.log(`✅ 获取项目 ${projectId} 的尾款记录,共 ${allFinalPayments.length} 条(来自Project.data)`);
return allFinalPayments.map((p: any) => mockParseObject);
}
createPayment() - 创建付款记录async createPayment(paymentData: {...}): Promise<FmodeObject> {
console.log('📊 [降级方案] 保存付款记录到 Project.data.payments...');
const projectQuery = new Parse.Query('Project');
const project = await projectQuery.get(paymentData.projectId);
const data = project.get('data') || {};
// 确保 payments 数组存在
if (!data.payments) {
data.payments = [];
}
// 创建新的付款记录对象
const newPayment: any = {
id: `payment_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
objectId: `payment_${Date.now()}`,
projectId: paymentData.projectId,
type: paymentData.type,
amount: paymentData.amount,
status: 'pending',
// ... 其他字段
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
};
// 添加到 payments 数组
data.payments.push(newPayment);
// 保存项目
project.set('data', data);
await project.save();
console.log(`✅ 创建付款记录成功(保存到Project.data.payments):`, newPayment.id);
return mockParseObject;
}
Project.data = {
// 所有付款记录
payments: [
{
id: "payment_1234567890_abc123",
objectId: "payment_1234567890",
projectId: "项目ID",
type: "advance" | "milestone" | "final" | "refund",
stage: "aftercare",
method: "支付方式",
amount: 金额,
currency: "CNY",
status: "pending" | "paid" | "overdue" | "cancelled",
recordedById: "记录人ID",
recordedDate: "2024-11-15T09:00:00.000Z",
paidById: "支付人ID",
description: "描述",
notes: "备注",
productId: "产品ID",
dueDate: "截止日期",
percentage: 百分比,
isDeleted: false,
createdAt: "2024-11-15T09:00:00.000Z",
updatedAt: "2024-11-15T09:00:00.000Z"
}
],
// 尾款专用记录(可选,与payments重复存储以提高查询效率)
finalPayments: [
// 同上,但只包含 type === 'final' 的记录
],
// 其他已有字段
quotation: {...},
unifiedSpaces: [...],
deliveryCompletedAt: Date,
// ...
}
QuotationEditorComponent
↓ (报价生成)
calculateTotal()
↓ (emit事件)
totalChange.emit(total)
↓ (父组件接收)
StageOrderComponent.onTotalChange(total)
↓ (更新本地数据)
this.quotation.total = total
↓ (显示在页面)
总报价:¥{{quotation.total}}
创建付款记录
↓
aftercareDataService.createPayment()
↓ (降级方案)
保存到 Project.data.payments[]
↓
项目保存成功
↓
读取付款记录
↓
aftercareDataService.getProjectPayments()
↓ (降级方案)
从 Project.data.payments[] 读取
↓
转换为 mockParseObject
↓
显示在尾款结算页面
查看控制台日志:
💰 [订单分配] 总报价更新: 12800
📊 [订单分配] 报价数据更新: {...}
验证页面显示正确的总报价金额
查看控制台日志:
📊 [降级方案] 从 Project.data.payments 获取付款记录...
✅ 获取项目 xxx 的付款记录,共 N 条(来自Project.data)
📊 [降级方案] 从 Project.data 获取尾款记录...
✅ 获取项目 xxx 的尾款记录,共 N 条(来自Project.data)
验证不再出现 ProjectPayment 表不存在的错误
验证尾款数据正常显示
QuotationEditorComponent)已有 totalChange 事件Project.data.payments 数组ProjectFile (payment_voucher) 降级读取finalPayments, final_payments, paymentsProject.data.payments 数组中ProjectPayment 表isDeleted: true)订单分配阶段
尾款结算阶段
性能优化
Project.data 的数据结构2024年11月15日 09:45
Cascade AI Assistant