✅ 已恢复订单分配阶段的必填验证逻辑
✅ 禁止用户点击导航栏跳过阶段
✅ 只允许访问当前阶段或已完成的阶段
修改内容:switchStage 方法添加权限验证
/**
* 切换阶段(点击顶部导航栏,无权限限制)
* 允许自由访问所有阶段,无论状态如何
*/
switchStage(stageId: string) {
const status = this.getStageStatus(stageId);
// ❌ 取消权限限制,允许访问所有阶段
console.log(`✅ 允许访问阶段: ${stageId} (状态: ${status})`);
// ❌ 直接导航,不验证
this.currentStage = stageId;
this.router.navigate([stageId], { relativeTo: this.route });
}
/**
* 切换阶段(添加权限验证)
* 只允许访问当前阶段或已完成的阶段
*/
switchStage(stageId: string) {
const status = this.getStageStatus(stageId);
// ✅ 关键验证:只允许访问当前阶段或已完成的阶段
if (status === 'pending') {
console.warn(`❌ 阶段 "${stageId}" 尚未开始,无法访问`);
const stageName = this.stages.find(s => s.id === stageId)?.name || stageId;
const currentStageName = this.stages.find(s => s.id === this.currentStage)?.name;
// ✅ 弹出友好提示
window?.fmode?.alert(
`无法进入"${stageName}"阶段\n\n` +
`请先完成"${currentStageName}"阶段的必填项:\n` +
`1. 填写项目基本信息\n` +
`2. 配置报价明细\n` +
`3. 分配设计师(或提交组长审批)`
);
return;
}
// ✅ 允许访问当前阶段或已完成的阶段
this.currentStage = stageId;
this.router.navigate([stageId], { relativeTo: this.route });
}
修改内容:导航栏添加条件判断,禁用未开始的阶段
<div
class="stage-item"
[class.clickable]="true" <!-- ❌ 所有阶段都可点击 -->
(click)="switchStage(stage.id)"> <!-- ❌ 没有条件判断 -->
<div
class="stage-item"
[class.clickable]="getStageStatus(stage.id) !== 'pending'" <!-- ✅ 只有非pending可点击 -->
[class.disabled]="getStageStatus(stage.id) === 'pending'" <!-- ✅ pending显示为禁用 -->
(click)="getStageStatus(stage.id) !== 'pending' && switchStage(stage.id)"> <!-- ✅ 添加条件 -->
修改内容:添加禁用状态的样式
// 禁用状态(未开始的阶段)
&.disabled {
cursor: not-allowed !important;
opacity: 0.5;
pointer-events: none; // 完全禁用点击
.stage-circle {
background-color: #f5f5f5;
border-color: #e0e0e0;
color: #999;
}
.stage-label {
color: #999;
}
// 取消悬停效果
&:hover {
transform: none;
.stage-circle {
box-shadow: none;
}
}
}
| 阶段状态 | 视觉效果 | 点击行为 | 说明 |
|---|---|---|---|
| pending(未开始) | 灰色,半透明,禁用鼠标 | ❌ 禁止点击,弹出提示 | 必须先完成当前阶段 |
| active(当前) | 红色,高亮,脉冲动画 | ✅ 允许点击,刷新页面 | 可以重新进入当前阶段 |
| completed(已完成) | 绿色,勾选图标 | ✅ 允许点击,回顾阶段 | 可以查看已完成的内容 |
必填项:(stage-order.component.ts 第1192-1223行)
设计师分配:(第1228-1331行)
提交方式:
完成条件:
提交方式:
stage:completed 事件完成条件:
提交方式:
stage:completed 事件【订单分配】
↓
填写必填信息
↓
分配设计师?
├─ 是 → 自动通过
└─ 否 → 提交组长审批 → 组长批准
↓
点击"确认订单"按钮
↓
验证必填项
├─ 通过 → 保存数据
└─ 失败 → 显示错误提示
↓
更新 project.currentStage = "确认需求"
↓
派发 stage:completed 事件
↓
路由自动跳转到"确认需求"
↓
【确认需求】阶段开始
用户点击导航栏阶段
↓
switchStage(stageId)
↓
getStageStatus(stageId)
↓
判断阶段状态
├─ pending(未开始)
│ → ❌ 禁止访问
│ → 弹出提示
│ → return
│
├─ active(当前)
│ → ✅ 允许访问
│ → 刷新当前页面
│
└─ completed(已完成)
→ ✅ 允许访问
→ 查看已完成内容
↓
导航到目标阶段
| 问题 | 修复前 ❌ | 修复后 ✅ |
|---|---|---|
| 阶段切换验证 | 无任何验证,可以随意跳转 | 只能访问当前或已完成阶段 |
| 导航栏点击 | 所有阶段都可点击 | 未开始的阶段禁用 |
| 视觉反馈 | 未开始的阶段看起来可点击 | 未开始的阶段灰色半透明 |
| 用户提示 | 无提示 | 友好的错误提示 |
| 鼠标样式 | 所有阶段都是指针 | 禁用阶段显示禁止图标 |
| 必填项验证 | 可以被绕过 | 必须通过提交按钮验证 |
if (status === 'pending') {
window?.fmode?.alert('无法进入该阶段,请先完成当前阶段');
return; // ✅ 禁止访问
}
window?.fmode?.alert(
`无法进入"${stageName}"阶段\n\n` +
`请先完成"${currentStageName}"阶段的必填项:\n` +
`1. 填写项目基本信息\n` +
`2. 配置报价明细\n` +
`3. 分配设计师(或提交组长审批)`
);
&.disabled {
cursor: not-allowed !important;
opacity: 0.5;
pointer-events: none; // 完全禁用点击
}
[class.disabled]="getStageStatus(stage.id) === 'pending'"
(click)="getStageStatus(stage.id) !== 'pending' && switchStage(stage.id)"
project-detail.component.ts - 添加权限验证逻辑project-detail.component.html - 禁用未开始的阶段project-detail.component.scss - 添加禁用样式只允许访问当前阶段或已完成的阶段,禁止跳过未完成的阶段。
必须通过点击"确认订单"/"确认需求"等按钮,完成必填项验证后,才能推进到下一阶段。