Browse Source

fix: order access

Future 1 ngày trước cách đây
mục cha
commit
b79bb9ff31

+ 53 - 0
docs/task/20251020-fix-product.md

@@ -0,0 +1,53 @@
+# 2025-10-20 修复与改版方案:多空间 Product 模型下的 StageOrder 与报价组件
+
+## 背景与问题定位
+- 当前页面卡在“加载订单信息...”,核心原因:StageOrder 使用 `ChangeDetectionStrategy.OnPush`,异步加载完成后未触发变更检查,`loading` 置为 `false` 未被视图采纳。
+- `loadDepartmentMembers` 的调用在 `loadData` 中传入了 `department.id`,而方法签名要求 `FmodeObject`,导致潜在运行时异常与列表加载失败。
+- 架构变更:`ProjectSpace` 迁移为以 `Product` 统一管理空间,报价、需求、交付整合到 `Project.data`,StageOrder 中保留了部分旧的空间与报价组织逻辑,需统一由 `quotation-editor` 组件基于 `Project.id` 驱动。
+
+## 目标
+- 页面稳定可用:修复加载状态与成员加载问题,使订单分配页可正常显示。
+- 报价逻辑收敛:将多空间报价、产品管理逻辑封装在 `quotation-editor`,StageOrder 仅透传 `project.id`、权限与用户信息。
+- 与 `schemas.md` 一致:遵循 `Product` 表为统一空间管理的范式,报价数据写回 `Project.data.quotation`。
+
+## 修复项与改动摘要
+1. OnPush 变更侦测修复
+   - 在 `StageOrderComponent` 构造函数中注入 `ChangeDetectorRef`。
+   - 在 `loadData` 与 `loadProjectSpaces` 的 `finally` 中调用 `cdr.markForCheck()`,确保 `loading` 与 `loadingSpaces` 更新后视图刷新。
+2. 调用参数纠正
+   - 在 `loadData` 内将 `await this.loadDepartmentMembers(department.id)` 改为传 `department` 对象:`await this.loadDepartmentMembers(department)`。
+3. 报价编辑器集成核验
+   - `app-quotation-editor` 已支持 `@Input() projectId: string`,并在 `ngOnInit/ngOnChanges` 自动加载 `Project`、`Product` 并生成或同步报价;`loadingChange` 事件会同步加载状态。
+   - StageOrder 中保留 `onQuotationChange/onTotalChange/onProductsChange` 用于接收报价结果与产品列表,但不再在页面内重复生成报价。
+
+## 设计与实现要点(多空间报价)
+- `quotation-editor` 负责:
+  - 通过 `projectId` 加载 `Project` 与其 `Product` 列表;当无产品时依据项目类型生成默认产品房间。
+  - 生成可编辑的工序(建模/软装/渲染/后期)的报价明细,计算各产品小计与总价。
+  - 将生成后的报价写回 `Project.data.quotation`,并通过事件输出到父组件。
+- StageOrder 负责:
+  - 展示客户信息、项目基本信息、部门与成员分配、项目文件处理。
+  - 通过 `app-quotation-editor [projectId]` 使用报价逻辑,无需维护 `quotation.spaces` 的内部冗余生成流程。
+
+## 风险与回退
+- 若 `Product` 表数据为空且项目类型未选择,默认产品生成会跳过;需在 UI 上引导选择项目类型后再生成报价。
+- 若企业微信环境拖拽不可用,文件上传路径已具备浏览器选择备选方案。
+
+## 验证计划
+- 启动开发服务器 `ng serve --port 4300`,打开项目详情 → 订单分配页。
+- 验证加载提示消失,客户/项目信息、报价编辑器渲染正常。
+- 切换项目类型生成默认产品,检查报价总价与产品占比明细是否更新并写回。
+- 选择项目组与成员,确认成员列表能正确加载并可分配。
+
+## 后续优化建议
+- 在 `StageOrder.onQuotationLoadingChange` 中联动顶层 `loading`(或独立 `quotationLoading`)以更细粒度展示报价加载状态。
+- 将旧的空间管理展示与 `Product` 映射进一步简化,减少维护重复结构。
+- 补充单元测试:
+  - `quotation-editor` 的报价生成与保存。
+  - `StageOrder` 的加载状态与成员加载行为。
+
+---
+
+## 变更日志
+- 修复 `StageOrder` OnPush 视图刷新与成员加载参数类型。
+- 保持 `quotation-editor` 以 `projectId` 驱动多空间报价生成与管理。

+ 2 - 2
src/modules/project/pages/project-detail/stages/stage-order.component.html

@@ -136,7 +136,7 @@
     </div>
 
     <!-- 3. 场景选择(家装) -->
-    @if (projectInfo.projectType === '家装' && projectInfo.renderType) {
+    @if (false) {
       <div class="card scene-card">
         <div class="card-header">
           <h3 class="card-title">
@@ -267,7 +267,7 @@
     }
 
     <!-- 3. 场景选择(工装) -->
-    @if (projectInfo.projectType === '工装') {
+    @if (false) {
       <div class="card scene-card">
         <div class="card-header">
           <h3 class="card-title">

+ 6 - 3
src/modules/project/pages/project-detail/stages/stage-order.component.ts

@@ -1,4 +1,4 @@
-import { Component, OnInit, Input, ViewChild, ElementRef, ChangeDetectionStrategy } from '@angular/core';
+import { Component, OnInit, Input, ViewChild, ElementRef, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { FormsModule } from '@angular/forms';
 import { ActivatedRoute } from '@angular/router';
@@ -204,7 +204,8 @@ export class StageOrderComponent implements OnInit {
   constructor(
     private route: ActivatedRoute,
     private projectFileService: ProjectFileService,
-    private productSpaceService: ProductSpaceService
+    private productSpaceService: ProductSpaceService,
+    private cdr: ChangeDetectorRef
   ) {
     this.checkWxWorkSupport();
   }
@@ -350,7 +351,7 @@ export class StageOrderComponent implements OnInit {
         const department = this.project.get('department');
         if (department) {
           this.selectedDepartment = department;
-          await this.loadDepartmentMembers(department.id);
+          await this.loadDepartmentMembers(department);
         }
 
         const assignee = this.project.get('assignee');
@@ -378,6 +379,7 @@ export class StageOrderComponent implements OnInit {
       console.error('加载失败:', err);
     } finally {
       this.loading = false;
+      this.cdr.markForCheck();
     }
   }
 
@@ -410,6 +412,7 @@ export class StageOrderComponent implements OnInit {
       console.error('加载项目空间失败:', error);
     } finally {
       this.loadingSpaces = false;
+      this.cdr.markForCheck();
     }
   }