用户反馈:订单分配阶段还没有填写必填信息和分配组员,点击顶部导航栏就可以直接进入其他阶段。
文件:project-detail.component.ts 第504-535行
/**
* 切换阶段(点击顶部导航栏,无权限限制)
* ❌ 允许自由访问所有阶段,无论状态如何
*/
switchStage(stageId: string) {
console.log('🔄 用户点击切换阶段:', stageId);
// ❌ 取消权限限制,允许访问所有阶段
console.log(`✅ 允许访问阶段: ${stageId} (状态: ${status})`);
// ❌ 直接更新状态,不验证
this.currentStage = stageId;
// ❌ 直接导航,不检查前置条件
this.router.navigate([stageId], { relativeTo: this.route });
}
问题:
文件:project-detail.component.html 第10-11行
<div
class="stage-item"
[class.clickable]="true" <!-- ❌ 所有阶段都可点击 -->
(click)="switchStage(stage.id)">
问题:所有阶段都标记为 clickable=true,没有根据阶段状态禁用未完成的阶段。
用户点击导航栏阶段
↓
检查目标阶段状态
↓
【情况1】目标阶段状态 = 'pending'(未开始)
→ ❌ 禁止跳转
→ 提示:"请先完成当前阶段"
↓
【情况2】目标阶段状态 = 'active'(当前阶段)
→ ✅ 允许跳转(刷新当前页面)
↓
【情况3】目标阶段状态 = 'completed'(已完成)
→ ✅ 允许跳转(可以回顾已完成的阶段)
必填项验证:(stage-order.component.ts 第1192-1223行)
// 1. 项目名称
if (!this.projectInfo.title.trim()) {
alert('请填写项目名称');
return;
}
// 2. 项目类型
if (!this.projectInfo.projectType) {
alert('请选择项目类型');
return;
}
// 3. 小图日期
if (!this.projectInfo.demoday) {
alert('请选择小图日期');
return;
}
// 4. 报价明细
if (this.quotation.total === 0) {
alert('请配置报价明细');
return;
}
设计师分配验证:(第1228-1237行)
// 检查是否已分配设计师
const query = new Parse.Query('ProjectTeam');
query.equalTo('project', this.project.toPointer());
query.notEqualTo('isDeleted', true);
const assignedTeams = await query.find();
const hasAssignedDesigners = assignedTeams.length > 0;
完成条件:
完成条件:(stage-requirements.component.ts)
完成条件:(stage-delivery.component.ts)
修改文件:project-detail.component.ts
/**
* 切换阶段(添加验证逻辑)
*/
switchStage(stageId: string) {
console.log('🔄 用户点击切换阶段:', stageId);
const status = this.getStageStatus(stageId);
// ✅ 验证1:只允许访问当前阶段或已完成的阶段
if (status === 'pending') {
console.warn('❌ 无法访问未开始的阶段:', stageId);
window?.fmode?.alert('请先完成当前阶段,再进入下一阶段');
return;
}
// ✅ 验证2:检查当前阶段是否已完成必填项(可选,根据需求)
// const canLeaveCurrentStage = await this.checkCurrentStageCompletion();
// if (!canLeaveCurrentStage) {
// window?.fmode?.alert('当前阶段还有未完成的必填项');
// return;
// }
// ✅ 允许访问当前阶段或已完成的阶段
console.log(`✅ 允许访问阶段: ${stageId} (状态: ${status})`);
this.currentStage = stageId;
this.router.navigate([stageId], { relativeTo: this.route })
.then(success => {
if (success) {
console.log('✅ 导航成功:', stageId);
} else {
console.warn('⚠️ 导航失败:', stageId);
}
})
.catch(err => {
console.error('❌ 导航出错:', err);
});
}
修改文件:project-detail.component.html
<div
class="stage-item"
[class.completed]="getStageStatus(stage.id) === 'completed'"
[class.active]="getStageStatus(stage.id) === 'active'"
[class.pending]="getStageStatus(stage.id) === 'pending'"
[class.clickable]="getStageStatus(stage.id) !== 'pending'" <!-- ✅ 只有非pending的阶段可点击 -->
[class.disabled]="getStageStatus(stage.id) === 'pending'" <!-- ✅ pending阶段显示为禁用 -->
(click)="getStageStatus(stage.id) !== 'pending' && switchStage(stage.id)"> <!-- ✅ 添加条件判断 -->
对应CSS:(在 project-detail.component.scss 中)
.stage-item {
&.disabled {
cursor: not-allowed;
opacity: 0.5;
pointer-events: none; // 禁用点击事件
}
&.clickable:not(.disabled) {
cursor: pointer;
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
}
}
文件:project-detail.component.ts 第504-535行
/**
* 切换阶段(添加权限验证)
* 只允许访问当前阶段或已完成的阶段
*/
switchStage(stageId: string) {
console.log('🔄 用户点击切换阶段:', stageId, {
currentRoute: this.router.url,
currentStage: this.currentStage,
workflowStage: this.project?.get('currentStage')
});
// 获取点击阶段的状态
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 || this.currentStage;
window?.fmode?.alert(
`无法进入"${stageName}"阶段\n\n` +
`请先完成"${currentStageName}"阶段的必填项:\n` +
`1. 填写项目基本信息\n` +
`2. 配置报价明细\n` +
`3. 分配设计师(或提交组长审批)`
);
return;
}
// ✅ 允许访问当前阶段或已完成的阶段
console.log(`✅ 允许访问阶段: ${stageId} (状态: ${status})`);
// 更新本地显示状态
this.currentStage = stageId;
// 导航到指定阶段
this.router.navigate([stageId], { relativeTo: this.route })
.then(success => {
if (success) {
console.log('✅ 导航成功:', stageId);
} else {
console.warn('⚠️ 导航失败:', stageId);
}
})
.catch(err => {
console.error('❌ 导航出错:', err);
});
}
文件:project-detail.component.html 第4-11行
@for (stage of stages; track stage.id) {
<div
class="stage-item"
[class.completed]="getStageStatus(stage.id) === 'completed'"
[class.active]="getStageStatus(stage.id) === 'active'"
[class.pending]="getStageStatus(stage.id) === 'pending'"
[class.clickable]="getStageStatus(stage.id) !== 'pending'"
[class.disabled]="getStageStatus(stage.id) === 'pending'"
(click)="getStageStatus(stage.id) !== 'pending' && switchStage(stage.id)">
<!-- 阶段内容 -->
</div>
<!-- ... -->
}
文件:project-detail.component.scss
.stage-item {
// ... 原有样式 ...
// ✅ 新增:禁用状态
&.disabled {
cursor: not-allowed !important;
opacity: 0.5;
pointer-events: none;
.stage-circle {
background: #e0e0e0;
border-color: #e0e0e0;
}
.stage-label {
color: #999;
}
}
// ✅ 修改:只有非禁用的可点击项才有hover效果
&.clickable:not(.disabled) {
cursor: pointer;
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
}
}
switchStage 方法完全取消了权限验证getStageStatus() 的返回值进行权限判断