quotation-details.component.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';
  2. import { CommonModule } from '@angular/common';
  3. import { FormsModule } from '@angular/forms';
  4. import { AIQuotationService, AIQuotationParams, AIQuotationResult } from '../../../../../services/ai-quotation.service';
  5. export interface QuotationItem {
  6. id: string;
  7. category: string;
  8. name: string;
  9. quantity: number;
  10. unit: string;
  11. unitPrice: number;
  12. description: string;
  13. }
  14. export interface QuotationData {
  15. items: QuotationItem[];
  16. totalAmount: number;
  17. materialCost: number;
  18. laborCost: number;
  19. designFee: number;
  20. managementFee: number;
  21. }
  22. @Component({
  23. selector: 'app-quotation-details',
  24. standalone: true,
  25. imports: [CommonModule, FormsModule],
  26. templateUrl: './quotation-details.component.html',
  27. styleUrls: ['./quotation-details.component.scss']
  28. })
  29. export class QuotationDetailsComponent implements OnInit {
  30. @Input() initialData?: QuotationData;
  31. @Output() dataChange = new EventEmitter<QuotationData>();
  32. quotationData: QuotationData = {
  33. items: [],
  34. totalAmount: 0,
  35. materialCost: 0,
  36. laborCost: 0,
  37. designFee: 0,
  38. managementFee: 0
  39. };
  40. // AI报价相关
  41. showAIModal = false;
  42. aiLoading = false;
  43. aiParams: AIQuotationParams = {
  44. area: 100,
  45. style: '现代简约',
  46. level: '舒适型',
  47. specialRequirements: ''
  48. };
  49. // 选项数据
  50. styleOptions: string[] = [];
  51. levelOptions: string[] = [];
  52. constructor(private aiQuotationService: AIQuotationService) {}
  53. ngOnInit() {
  54. if (this.initialData) {
  55. this.quotationData = { ...this.initialData };
  56. }
  57. // 初始化选项数据
  58. this.styleOptions = this.aiQuotationService.getStyleOptions();
  59. this.levelOptions = this.aiQuotationService.getLevelOptions();
  60. }
  61. // 添加报价项目
  62. addQuotationItem() {
  63. const newItem: QuotationItem = {
  64. id: Date.now().toString(),
  65. category: '客餐厅',
  66. name: '',
  67. quantity: 1,
  68. unit: '㎡',
  69. unitPrice: 0,
  70. description: ''
  71. };
  72. this.quotationData.items.push(newItem);
  73. this.calculateTotal();
  74. this.emitDataChange();
  75. }
  76. // 删除报价项目
  77. removeQuotationItem(index: number) {
  78. this.quotationData.items.splice(index, 1);
  79. this.calculateTotal();
  80. this.emitDataChange();
  81. }
  82. // 复制报价项目
  83. duplicateQuotationItem(index: number) {
  84. const originalItem = this.quotationData.items[index];
  85. const duplicatedItem: QuotationItem = {
  86. ...originalItem,
  87. id: Date.now().toString(),
  88. name: originalItem.name + ' (副本)'
  89. };
  90. this.quotationData.items.splice(index + 1, 0, duplicatedItem);
  91. this.calculateTotal();
  92. this.emitDataChange();
  93. }
  94. // 计算总金额
  95. calculateTotal() {
  96. const materialCost = this.quotationData.items.reduce((sum, item) => sum + (item.quantity * item.unitPrice), 0);
  97. this.quotationData.materialCost = materialCost;
  98. this.quotationData.laborCost = materialCost * 0.3; // 人工费按材料费30%计算
  99. this.quotationData.designFee = materialCost * 0.05; // 设计费按材料费5%计算
  100. this.quotationData.managementFee = materialCost * 0.08; // 管理费按材料费8%计算
  101. this.quotationData.totalAmount = this.quotationData.materialCost + this.quotationData.laborCost + this.quotationData.designFee + this.quotationData.managementFee;
  102. }
  103. // 获取总金额
  104. getTotalAmount(): number {
  105. return this.quotationData.totalAmount;
  106. }
  107. // 获取材料费用
  108. getMaterialCost(): number {
  109. return this.quotationData.materialCost;
  110. }
  111. // 获取人工费用
  112. getLaborCost(): number {
  113. return this.quotationData.laborCost;
  114. }
  115. // 格式化金额显示
  116. formatAmount(amount: number): string {
  117. return amount.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
  118. }
  119. // 项目数据变化处理
  120. onItemChange() {
  121. this.calculateTotal();
  122. this.emitDataChange();
  123. }
  124. // 发送数据变化事件
  125. private emitDataChange() {
  126. this.dataChange.emit({ ...this.quotationData });
  127. }
  128. // 显示AI报价模态框
  129. showAIQuotation() {
  130. this.showAIModal = true;
  131. }
  132. // 关闭AI报价模态框
  133. closeAIModal() {
  134. this.showAIModal = false;
  135. this.aiLoading = false;
  136. }
  137. // 生成AI报价
  138. generateAIQuotation() {
  139. if (!this.aiParams.area || !this.aiParams.style || !this.aiParams.level) {
  140. return;
  141. }
  142. this.aiLoading = true;
  143. this.aiQuotationService.generateQuotation(this.aiParams).subscribe({
  144. next: (result: AIQuotationResult) => {
  145. // 将AI生成的项目转换为报价项目
  146. const aiItems: QuotationItem[] = result.items.map(item => ({
  147. id: Date.now().toString() + Math.random().toString(36).substr(2, 9),
  148. category: item.category,
  149. name: item.name,
  150. quantity: item.quantity,
  151. unit: item.unit,
  152. unitPrice: item.unitPrice,
  153. description: item.description || ''
  154. }));
  155. // 替换当前报价项目
  156. this.quotationData.items = aiItems;
  157. this.calculateTotal();
  158. this.emitDataChange();
  159. this.aiLoading = false;
  160. this.closeAIModal();
  161. },
  162. error: (error) => {
  163. console.error('AI报价生成失败:', error);
  164. this.aiLoading = false;
  165. }
  166. });
  167. }
  168. }