将订单分配阶段(StageOrderComponent)拆分为多个可复用的子组件,提高代码的可维护性、可测试性和可复用性。
stage-order/
├── components/ # 子组件目录
│ ├── approval-status-banner/ # 审批状态横幅
│ │ ├── approval-status-banner.component.ts
│ │ ├── approval-status-banner.component.html
│ │ └── approval-status-banner.component.scss
│ ├── leader-approval-bar/ # 组长审批操作条
│ │ ├── leader-approval-bar.component.ts
│ │ ├── leader-approval-bar.component.html
│ │ └── leader-approval-bar.component.scss
│ ├── project-basic-info/ # 项目基本信息
│ │ ├── project-basic-info.component.ts
│ │ ├── project-basic-info.component.html
│ │ └── project-basic-info.component.scss
│ └── order-action-buttons/ # 操作按钮
│ ├── order-action-buttons.component.ts
│ ├── order-action-buttons.component.html
│ └── order-action-buttons.component.scss
├── stage-order.component.ts # 主组件
├── stage-order.component.html # 主组件模板
└── stage-order.component.scss # 主组件样式
职责:显示订单审批状态(待审批、已通过、已驳回)
输入属性:
status: ApprovalStatus | null - 审批状态rejectionReason: string - 驳回原因输出事件:
resubmit: void - 重新提交事件使用示例:
<app-approval-status-banner
[status]="getApprovalStatus()"
[rejectionReason]="getRejectionReason()"
(resubmit)="prepareResubmit()">
</app-approval-status-banner>
特性:
职责:提供组长审批订单的操作按钮
输入属性:
saving: boolean - 是否正在保存输出事件:
approve: void - 通过审批事件reject: void - 驳回订单事件使用示例:
<app-leader-approval-bar
[saving]="saving"
(approve)="approveOrder()"
(reject)="rejectOrder()">
</app-leader-approval-bar>
特性:
职责:可折叠的项目基本信息表单
输入属性:
projectInfo: ProjectInfo - 项目信息对象expanded: boolean - 是否展开canEdit: boolean - 是否可编辑输出事件:
expandedChange: boolean - 展开状态变化projectInfoChange: ProjectInfo - 项目信息变化projectTypeChange: string - 项目类型变化接口定义:
export interface ProjectInfo {
title: string;
projectType: string;
renderType: string;
demoday: Date | null;
deadline: Date | null;
description: string;
priceLevel: string;
spaceType: string;
}
使用示例:
<app-project-basic-info
[projectInfo]="projectInfo"
[expanded]="projectInfoExpanded"
[canEdit]="canEdit"
(expandedChange)="projectInfoExpanded = $event"
(projectInfoChange)="onProjectInfoChange($event)"
(projectTypeChange)="onProjectTypeChange($event)">
</app-project-basic-info>
特性:
职责:提供保存草稿和确认订单操作
输入属性:
canEdit: boolean - 是否可编辑saving: boolean - 是否正在保存submittedPending: boolean - 是否已提交待审批approvalStatus: string | null - 审批状态输出事件:
saveDraft: void - 保存草稿事件submit: void - 提交订单事件使用示例:
<app-order-action-buttons
[canEdit]="canEdit"
[saving]="saving"
[submittedPending]="submittedPending"
[approvalStatus]="getApprovalStatus()"
(saveDraft)="saveDraft()"
(submit)="submitForOrder()">
</app-order-action-buttons>
特性:
<div class="stage-order-container">
<!-- 1. 审批状态横幅 -->
@if (project) {
<app-approval-status-banner
[status]="getApprovalStatus()"
[rejectionReason]="getRejectionReason()"
(resubmit)="prepareResubmit()">
</app-approval-status-banner>
}
<!-- 2. 组长审批操作条 -->
@if (getApprovalStatus() === 'pending' && isTeamLeader && !isFromCustomerService) {
<app-leader-approval-bar
[saving]="saving"
(approve)="approveOrder()"
(reject)="rejectOrder()">
</app-leader-approval-bar>
}
<!-- 3. 项目基本信息 -->
<app-project-basic-info
[projectInfo]="projectInfo"
[expanded]="projectInfoExpanded"
[canEdit]="canEdit"
(expandedChange)="projectInfoExpanded = $event"
(projectInfoChange)="onProjectInfoChange($event)"
(projectTypeChange)="onProjectTypeChange($event)">
</app-project-basic-info>
<!-- 4. 产品报价管理(已有组件) -->
<div class="card quotation-card">
<app-quotation-editor ...>
</app-quotation-editor>
</div>
<!-- 5. 设计师分配(已有组件) -->
<app-team-assign ...>
</app-team-assign>
<!-- 6. 操作按钮 -->
<app-order-action-buttons
[canEdit]="canEdit"
[saving]="saving"
[submittedPending]="submittedPending"
[approvalStatus]="getApprovalStatus()"
(saveDraft)="saveDraft()"
(submit)="submitForOrder()">
</app-order-action-buttons>
</div>
import { ApprovalStatusBannerComponent } from './components/approval-status-banner/approval-status-banner.component';
import { LeaderApprovalBarComponent } from './components/leader-approval-bar/leader-approval-bar.component';
import { ProjectBasicInfoComponent } from './components/project-basic-info/project-basic-info.component';
import { OrderActionButtonsComponent } from './components/order-action-buttons/order-action-buttons.component';
@Component({
selector: 'app-stage-order',
standalone: true,
imports: [
CommonModule,
FormsModule,
QuotationEditorComponent,
TeamAssignComponent,
CustomDatePickerComponent,
ApprovalStatusBannerComponent, // 新增
LeaderApprovalBarComponent, // 新增
ProjectBasicInfoComponent, // 新增
OrderActionButtonsComponent // 新增
],
...
})
单一大组件:
模块化小组件:
每个子组件都有独立的样式文件,避免样式冲突:
approval-status-banner.component.scss # 横幅样式
leader-approval-bar.component.scss # 审批栏样式
project-basic-info.component.scss # 表单样式
order-action-buttons.component.scss # 按钮样式
stage-order.component.scss # 主组件布局样式
公共样式可以提取到:
每个子组件都可以独立测试:
// approval-status-banner.component.spec.ts
describe('ApprovalStatusBannerComponent', () => {
it('should display pending status', () => {
component.status = 'pending';
fixture.detectChanges();
expect(compiled.querySelector('.status-icon').textContent).toBe('⏳');
});
it('should emit resubmit event', () => {
spyOn(component.resubmit, 'emit');
component.onResubmit();
expect(component.resubmit.emit).toHaveBeenCalled();
});
});
测试主组件与子组件的交互:
// stage-order.component.spec.ts
describe('StageOrderComponent', () => {
it('should pass approval status to banner component', () => {
const banner = fixture.debugElement.query(By.directive(ApprovalStatusBannerComponent));
expect(banner.componentInstance.status).toBe('pending');
});
});
所有子组件都实现了移动端优化:
// 移动端优化 (≤480px)
@media (max-width: 480px) {
// 横幅纵向布局,居中显示
.approval-status-banner {
flex-direction: column;
text-align: center;
}
// 审批按钮纵向排列,占满宽度
.leader-approval-bar {
.approval-buttons-container {
flex-direction: column;
button { width: 100%; }
}
}
// 表单输入框增大触摸区域
.form-input {
min-height: 44px;
padding: 12px;
}
}
✅ 已创建所有子组件文件
// stage-order.component.ts
// 1. 导入子组件
import { ApprovalStatusBannerComponent } from './components/approval-status-banner/approval-status-banner.component';
// ... 其他导入
// 2. 添加到imports数组
@Component({
imports: [
// ... 现有导入
ApprovalStatusBannerComponent,
LeaderApprovalBarComponent,
ProjectBasicInfoComponent,
OrderActionButtonsComponent
]
})
// 3. 添加事件处理方法(如果需要)
onProjectInfoChange(info: ProjectInfo): void {
this.projectInfo = info;
// 触发变更检测或其他操作
}
将原有的HTML块替换为子组件标签
将已移到子组件的样式从主组件SCSS中删除
主组件 (StageOrderComponent)
↓ @Input
子组件 (ApprovalStatusBannerComponent)
↓ @Output
主组件 (StageOrderComponent)
这些组件可以在其他地方复用:
| 文件 | 行数 | 说明 |
|---|---|---|
| stage-order.component.html | 230行 | 所有HTML在一个文件 |
| stage-order.component.scss | 3024行 | 所有样式在一个文件 |
| stage-order.component.ts | 2170行 | 所有逻辑在一个文件 |
| 总计 | 5424行 |
| 文件 | 行数 | 说明 |
|---|---|---|
| 主组件 | ||
| stage-order.component.html | ~80行 | 组件编排 |
| stage-order.component.scss | ~500行 | 布局样式 |
| stage-order.component.ts | ~1500行 | 主要逻辑 |
| 子组件 | ||
| approval-status-banner | ~200行 | 3个文件 |
| leader-approval-bar | ~150行 | 3个文件 |
| project-basic-info | ~400行 | 3个文件 |
| order-action-buttons | ~150行 | 3个文件 |
| 总计 | ~3000行 | 13个文件 |
优势:
创建时间:2024-12-09
状态:✅ 子组件创建完成,待集成到主组件