|
@@ -25,7 +25,8 @@ import { QuotationDetailsComponent, QuotationData } from './components/quotation
|
|
|
import { DesignerAssignmentComponent, DesignerAssignmentData, Designer as AssignmentDesigner } from './components/designer-assignment/designer-assignment.component';
|
|
import { DesignerAssignmentComponent, DesignerAssignmentData, Designer as AssignmentDesigner } from './components/designer-assignment/designer-assignment.component';
|
|
|
// 引入客户服务模块的设计师日历组件
|
|
// 引入客户服务模块的设计师日历组件
|
|
|
import { DesignerCalendarComponent, Designer as CalendarDesigner, ProjectGroup as CalendarProjectGroup } from '../../customer-service/consultation-order/components/designer-calendar/designer-calendar.component';
|
|
import { DesignerCalendarComponent, Designer as CalendarDesigner, ProjectGroup as CalendarProjectGroup } from '../../customer-service/consultation-order/components/designer-calendar/designer-calendar.component';
|
|
|
-import { UploadSuccessModalComponent } from '../../../shared/components/upload-success-modal/upload-success-modal.component';
|
|
|
|
|
|
|
+// 引入参考图管理组件
|
|
|
|
|
+import { ReferenceImageManagerComponent } from './components/reference-image-manager/reference-image-manager.component';
|
|
|
|
|
|
|
|
import { ColorAnalysisResult, ColorAnalysisService } from '../../../shared/services/color-analysis.service';
|
|
import { ColorAnalysisResult, ColorAnalysisService } from '../../../shared/services/color-analysis.service';
|
|
|
|
|
|
|
@@ -264,7 +265,7 @@ interface DeliveryProcess {
|
|
|
@Component({
|
|
@Component({
|
|
|
selector: 'app-project-detail',
|
|
selector: 'app-project-detail',
|
|
|
standalone: true,
|
|
standalone: true,
|
|
|
- imports: [CommonModule, FormsModule, ReactiveFormsModule, RequirementsConfirmCardComponent, SettlementCardComponent, CustomerReviewCardComponent, CustomerReviewFormComponent, ComplaintCardComponent, PanoramicSynthesisCardComponent, QuotationDetailsComponent, DesignerAssignmentComponent, DesignerCalendarComponent, UploadSuccessModalComponent],
|
|
|
|
|
|
|
+ imports: [CommonModule, FormsModule, ReactiveFormsModule, RequirementsConfirmCardComponent, SettlementCardComponent, CustomerReviewCardComponent, CustomerReviewFormComponent, ComplaintCardComponent, PanoramicSynthesisCardComponent, QuotationDetailsComponent, DesignerAssignmentComponent, DesignerCalendarComponent, ReferenceImageManagerComponent],
|
|
|
templateUrl: './project-detail.html',
|
|
templateUrl: './project-detail.html',
|
|
|
styleUrls: ['./project-detail.scss', './debug-styles.scss', './horizontal-panel.scss']
|
|
styleUrls: ['./project-detail.scss', './debug-styles.scss', './horizontal-panel.scss']
|
|
|
})
|
|
})
|
|
@@ -287,6 +288,9 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
showDropdown: boolean = false;
|
|
showDropdown: boolean = false;
|
|
|
currentStage: string = '';
|
|
currentStage: string = '';
|
|
|
|
|
|
|
|
|
|
+ // 新增:只读复盘模式(从财务工作台跳转)
|
|
|
|
|
+ isReviewOnlyMode: boolean = false;
|
|
|
|
|
+
|
|
|
// 新增:尾款结算完成状态
|
|
// 新增:尾款结算完成状态
|
|
|
isSettlementCompleted: boolean = false;
|
|
isSettlementCompleted: boolean = false;
|
|
|
isConfirmingSettlement: boolean = false;
|
|
isConfirmingSettlement: boolean = false;
|
|
@@ -302,7 +306,7 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
// 客户信息卡片展开/收起状态
|
|
// 客户信息卡片展开/收起状态
|
|
|
isCustomerInfoExpanded: boolean = false;
|
|
isCustomerInfoExpanded: boolean = false;
|
|
|
|
|
|
|
|
- // 新增:订单创建表单相关
|
|
|
|
|
|
|
+ // 新增:订单分配表单相关
|
|
|
orderCreationForm!: FormGroup;
|
|
orderCreationForm!: FormGroup;
|
|
|
optionalForm!: FormGroup;
|
|
optionalForm!: FormGroup;
|
|
|
isOptionalFormExpanded: boolean = false;
|
|
isOptionalFormExpanded: boolean = false;
|
|
@@ -342,10 +346,10 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
isAnalyzingColors = false;
|
|
isAnalyzingColors = false;
|
|
|
|
|
|
|
|
// 新增:9阶段顺序(串式流程)- 包含后期阶段
|
|
// 新增:9阶段顺序(串式流程)- 包含后期阶段
|
|
|
- stageOrder: ProjectStage[] = ['订单创建', '需求沟通', '方案确认', '建模', '软装', '渲染', '后期', '尾款结算', '客户评价', '投诉处理'];
|
|
|
|
|
|
|
+ stageOrder: ProjectStage[] = ['订单分配', '需求沟通', '方案确认', '建模', '软装', '渲染', '后期', '尾款结算', '客户评价', '投诉处理'];
|
|
|
// 新增:阶段展开状态(默认全部收起,当前阶段在数据加载后自动展开)
|
|
// 新增:阶段展开状态(默认全部收起,当前阶段在数据加载后自动展开)
|
|
|
expandedStages: Partial<Record<ProjectStage, boolean>> = {
|
|
expandedStages: Partial<Record<ProjectStage, boolean>> = {
|
|
|
- '订单创建': false,
|
|
|
|
|
|
|
+ '订单分配': false,
|
|
|
'需求沟通': false,
|
|
'需求沟通': false,
|
|
|
'方案确认': false,
|
|
'方案确认': false,
|
|
|
'建模': false,
|
|
'建模': false,
|
|
@@ -359,7 +363,7 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
|
|
|
|
|
// 新增:四大板块定义与展开状态 - 交付执行板块调整为三个阶段
|
|
// 新增:四大板块定义与展开状态 - 交付执行板块调整为三个阶段
|
|
|
sections: Array<{ key: SectionKey; label: string; stages: ProjectStage[] }> = [
|
|
sections: Array<{ key: SectionKey; label: string; stages: ProjectStage[] }> = [
|
|
|
- { key: 'order', label: '订单创建', stages: ['订单创建'] },
|
|
|
|
|
|
|
+ { key: 'order', label: '订单分配', stages: ['订单分配'] },
|
|
|
{ key: 'requirements', label: '确认需求', stages: ['需求沟通', '方案确认'] },
|
|
{ key: 'requirements', label: '确认需求', stages: ['需求沟通', '方案确认'] },
|
|
|
{ key: 'delivery', label: '交付执行', stages: ['建模', '软装', '渲染', '后期'] },
|
|
{ key: 'delivery', label: '交付执行', stages: ['建模', '软装', '渲染', '后期'] },
|
|
|
{ key: 'aftercare', label: '售后', stages: [] }
|
|
{ key: 'aftercare', label: '售后', stages: [] }
|
|
@@ -376,11 +380,12 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
showExceptionForm: boolean = false;
|
|
showExceptionForm: boolean = false;
|
|
|
|
|
|
|
|
// 标签页相关
|
|
// 标签页相关
|
|
|
- activeTab: 'progress' | 'members' | 'files' = 'progress';
|
|
|
|
|
- tabs: Array<{ id: 'progress' | 'members' | 'files'; name: string }> = [
|
|
|
|
|
|
|
+ activeTab: 'progress' | 'members' | 'files' | 'reference' = 'progress';
|
|
|
|
|
+ tabs: Array<{ id: 'progress' | 'members' | 'files' | 'reference'; name: string }> = [
|
|
|
{ id: 'progress', name: '项目进度' },
|
|
{ id: 'progress', name: '项目进度' },
|
|
|
{ id: 'members', name: '项目成员' },
|
|
{ id: 'members', name: '项目成员' },
|
|
|
- { id: 'files', name: '项目文件' }
|
|
|
|
|
|
|
+ { id: 'files', name: '项目文件' },
|
|
|
|
|
+ { id: 'reference', name: '参考图管理' }
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
// 标准化阶段(视图层映射)
|
|
// 标准化阶段(视图层映射)
|
|
@@ -507,12 +512,12 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
) {}
|
|
) {}
|
|
|
|
|
|
|
|
// 切换标签页
|
|
// 切换标签页
|
|
|
- switchTab(tabId: 'progress' | 'members' | 'files') {
|
|
|
|
|
|
|
+ switchTab(tabId: 'progress' | 'members' | 'files' | 'reference') {
|
|
|
this.activeTab = tabId;
|
|
this.activeTab = tabId;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 类型安全的标签页检查方法
|
|
// 类型安全的标签页检查方法
|
|
|
- isActiveTab(tabId: 'progress' | 'members' | 'files'): boolean {
|
|
|
|
|
|
|
+ isActiveTab(tabId: 'progress' | 'members' | 'files' | 'reference'): boolean {
|
|
|
return this.activeTab === tabId;
|
|
return this.activeTab === tabId;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -544,26 +549,26 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
this.router.navigate([], { relativeTo: this.route, queryParamsHandling: 'merge', queryParams: { id: projectId } });
|
|
this.router.navigate([], { relativeTo: this.route, queryParamsHandling: 'merge', queryParams: { id: projectId } });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 检查是否处于订单创建阶段,用于红色高亮显示
|
|
|
|
|
|
|
+ // 检查是否处于订单分配阶段,用于红色高亮显示
|
|
|
isCurrentOrderCreation(): boolean {
|
|
isCurrentOrderCreation(): boolean {
|
|
|
- // 只有当订单创建阶段是当前活跃阶段时才标红显示
|
|
|
|
|
|
|
+ // 只有当订单分配阶段是当前活跃阶段时才标红显示
|
|
|
// 修复逻辑:完成前序环节后才标红当前阶段
|
|
// 修复逻辑:完成前序环节后才标红当前阶段
|
|
|
const currentStage = this.project?.currentStage;
|
|
const currentStage = this.project?.currentStage;
|
|
|
if (!currentStage) return false;
|
|
if (!currentStage) return false;
|
|
|
|
|
|
|
|
- // 如果当前阶段就是订单创建阶段,说明需要标红显示
|
|
|
|
|
- if (currentStage === '订单创建') return true;
|
|
|
|
|
|
|
+ // 如果当前阶段就是订单分配阶段,说明需要标红显示
|
|
|
|
|
+ if (currentStage === '订单分配') return true;
|
|
|
|
|
|
|
|
- // 如果当前阶段在订单创建之后,说明订单创建已完成,不应标红
|
|
|
|
|
|
|
+ // 如果当前阶段在订单分配之后,说明订单分配已完成,不应标红
|
|
|
const stageOrder = [
|
|
const stageOrder = [
|
|
|
- '订单创建', '需求沟通', '方案确认', '建模', '软装',
|
|
|
|
|
|
|
+ '订单分配', '需求沟通', '方案确认', '建模', '软装',
|
|
|
'渲染', '尾款结算', '客户评价', '投诉处理'
|
|
'渲染', '尾款结算', '客户评价', '投诉处理'
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
const currentIndex = stageOrder.indexOf(currentStage);
|
|
const currentIndex = stageOrder.indexOf(currentStage);
|
|
|
- const orderCreationIndex = stageOrder.indexOf('订单创建');
|
|
|
|
|
|
|
+ const orderCreationIndex = stageOrder.indexOf('订单分配');
|
|
|
|
|
|
|
|
- // 如果当前阶段在订单创建之后,说明订单创建已完成
|
|
|
|
|
|
|
+ // 如果当前阶段在订单分配之后,说明订单分配已完成
|
|
|
return currentIndex <= orderCreationIndex;
|
|
return currentIndex <= orderCreationIndex;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -578,7 +583,7 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
|
|
|
|
|
// 定义阶段顺序
|
|
// 定义阶段顺序
|
|
|
const stageOrder = [
|
|
const stageOrder = [
|
|
|
- '订单创建', '需求沟通', '方案确认', '建模', '软装',
|
|
|
|
|
|
|
+ '订单分配', '需求沟通', '方案确认', '建模', '软装',
|
|
|
'渲染', '尾款结算', '客户评价', '投诉处理'
|
|
'渲染', '尾款结算', '客户评价', '投诉处理'
|
|
|
];
|
|
];
|
|
|
|
|
|
|
@@ -623,6 +628,26 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ngOnInit(): void {
|
|
ngOnInit(): void {
|
|
|
|
|
+ // 检查是否为只读复盘模式(从财务工作台跳转)
|
|
|
|
|
+ this.route.queryParams.subscribe(params => {
|
|
|
|
|
+ if (params['view'] === 'review-only') {
|
|
|
|
|
+ this.isReviewOnlyMode = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 检查是否需要直接定位到售后板块
|
|
|
|
|
+ if (params['section'] === 'aftercare' || params['view'] === 'review-only') {
|
|
|
|
|
+ // 自动切换到售后板块
|
|
|
|
|
+ this.expandedSection = 'aftercare';
|
|
|
|
|
+ // 滚动到项目复盘区域
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ const reviewSection = document.querySelector('.project-review-section');
|
|
|
|
|
+ if (reviewSection) {
|
|
|
|
|
+ reviewSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 500);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
// 初始化表单
|
|
// 初始化表单
|
|
|
this.initializeForms();
|
|
this.initializeForms();
|
|
|
|
|
|
|
@@ -658,12 +683,12 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
this.route.queryParamMap.subscribe({
|
|
this.route.queryParamMap.subscribe({
|
|
|
next: (qp) => {
|
|
next: (qp) => {
|
|
|
const raw = qp.get('activeTab');
|
|
const raw = qp.get('activeTab');
|
|
|
- const alias: Record<string, 'progress' | 'members' | 'files'> = {
|
|
|
|
|
|
|
+ const alias: Record<string, 'progress' | 'members' | 'files' | 'reference'> = {
|
|
|
requirements: 'progress',
|
|
requirements: 'progress',
|
|
|
overview: 'progress'
|
|
overview: 'progress'
|
|
|
};
|
|
};
|
|
|
const tab = raw && (raw in alias ? alias[raw] : raw);
|
|
const tab = raw && (raw in alias ? alias[raw] : raw);
|
|
|
- if (tab === 'progress' || tab === 'members' || tab === 'files') {
|
|
|
|
|
|
|
+ if (tab === 'progress' || tab === 'members' || tab === 'files' || tab === 'reference') {
|
|
|
this.activeTab = tab;
|
|
this.activeTab = tab;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -697,7 +722,7 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
// 设置同步状态
|
|
// 设置同步状态
|
|
|
this.isSyncingCustomerInfo = true;
|
|
this.isSyncingCustomerInfo = true;
|
|
|
|
|
|
|
|
- // 存储订单创建数据用于显示
|
|
|
|
|
|
|
+ // 存储订单分配数据用于显示
|
|
|
this.orderCreationData = syncData;
|
|
this.orderCreationData = syncData;
|
|
|
|
|
|
|
|
// 更新projectData以传递给子组件
|
|
// 更新projectData以传递给子组件
|
|
@@ -864,7 +889,7 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
// 只读规则:客服视角为只读
|
|
// 只读规则:客服视角为只读
|
|
|
isReadOnly(): boolean { return this.isCustomerServiceView(); }
|
|
isReadOnly(): boolean { return this.isCustomerServiceView(); }
|
|
|
|
|
|
|
|
- // 权限控制:客服只能编辑订单创建、确认需求、售后板块
|
|
|
|
|
|
|
+ // 权限控制:客服只能编辑订单分配、确认需求、售后板块
|
|
|
canEditSection(sectionKey: SectionKey): boolean {
|
|
canEditSection(sectionKey: SectionKey): boolean {
|
|
|
if (this.isCustomerServiceView()) {
|
|
if (this.isCustomerServiceView()) {
|
|
|
return sectionKey === 'order' || sectionKey === 'requirements' || sectionKey === 'aftercare';
|
|
return sectionKey === 'order' || sectionKey === 'requirements' || sectionKey === 'aftercare';
|
|
@@ -876,7 +901,7 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
canEditStage(stage: ProjectStage): boolean {
|
|
canEditStage(stage: ProjectStage): boolean {
|
|
|
if (this.isCustomerServiceView()) {
|
|
if (this.isCustomerServiceView()) {
|
|
|
const editableStages: ProjectStage[] = [
|
|
const editableStages: ProjectStage[] = [
|
|
|
- '订单创建', '需求沟通', '方案确认', // 订单创建和确认需求板块
|
|
|
|
|
|
|
+ '订单分配', '需求沟通', '方案确认', // 订单分配和确认需求板块
|
|
|
'尾款结算', '客户评价', '投诉处理' // 售后板块
|
|
'尾款结算', '客户评价', '投诉处理' // 售后板块
|
|
|
];
|
|
];
|
|
|
return editableStages.includes(stage);
|
|
return editableStages.includes(stage);
|
|
@@ -892,7 +917,7 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 返回当前板块的全部阶段(所有角色一致):
|
|
// 返回当前板块的全部阶段(所有角色一致):
|
|
|
- // 设计师也可查看 订单创建/确认需求/售后 板块内容
|
|
|
|
|
|
|
+ // 设计师也可查看 订单分配/确认需求/售后 板块内容
|
|
|
getVisibleStages(): ProjectStage[] {
|
|
getVisibleStages(): ProjectStage[] {
|
|
|
const activeKey = this.getActiveSectionKey();
|
|
const activeKey = this.getActiveSectionKey();
|
|
|
const sec = this.sections.find(s => s.key === activeKey);
|
|
const sec = this.sections.find(s => s.key === activeKey);
|
|
@@ -1414,7 +1439,7 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
// 将现有细分阶段映射为标准化阶段
|
|
// 将现有细分阶段映射为标准化阶段
|
|
|
mapToStandardPhase(stage: ProjectStage): '待分配' | '需求方案' | '项目执行' | '收尾验收' | '归档' {
|
|
mapToStandardPhase(stage: ProjectStage): '待分配' | '需求方案' | '项目执行' | '收尾验收' | '归档' {
|
|
|
const mapping: Record<ProjectStage, '待分配' | '需求方案' | '项目执行' | '收尾验收' | '归档'> = {
|
|
const mapping: Record<ProjectStage, '待分配' | '需求方案' | '项目执行' | '收尾验收' | '归档'> = {
|
|
|
- '订单创建': '待分配',
|
|
|
|
|
|
|
+ '订单分配': '待分配',
|
|
|
'需求沟通': '需求方案',
|
|
'需求沟通': '需求方案',
|
|
|
'方案确认': '需求方案',
|
|
'方案确认': '需求方案',
|
|
|
'建模': '项目执行',
|
|
'建模': '项目执行',
|
|
@@ -2121,7 +2146,7 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
// 根据阶段映射所属板块
|
|
// 根据阶段映射所属板块
|
|
|
getSectionKeyForStage(stage: ProjectStage): SectionKey {
|
|
getSectionKeyForStage(stage: ProjectStage): SectionKey {
|
|
|
switch (stage) {
|
|
switch (stage) {
|
|
|
- case '订单创建':
|
|
|
|
|
|
|
+ case '订单分配':
|
|
|
return 'order';
|
|
return 'order';
|
|
|
case '需求沟通':
|
|
case '需求沟通':
|
|
|
case '方案确认':
|
|
case '方案确认':
|
|
@@ -2145,8 +2170,8 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
// 优先使用本地的currentStage,如果没有则使用project.currentStage
|
|
// 优先使用本地的currentStage,如果没有则使用project.currentStage
|
|
|
const current = (this.currentStage || this.project?.currentStage) as ProjectStage | undefined;
|
|
const current = (this.currentStage || this.project?.currentStage) as ProjectStage | undefined;
|
|
|
|
|
|
|
|
- // 如果没有当前阶段(新创建的项目),默认订单创建板块为active(红色)
|
|
|
|
|
- if (!current || current === '订单创建') {
|
|
|
|
|
|
|
+ // 如果没有当前阶段(新创建的项目),默认订单分配板块为active(红色)
|
|
|
|
|
+ if (!current || current === '订单分配') {
|
|
|
return key === 'order' ? 'active' : 'pending';
|
|
return key === 'order' ? 'active' : 'pending';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -2185,7 +2210,7 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
// 阶段到锚点的映射
|
|
// 阶段到锚点的映射
|
|
|
stageToAnchor(stage: ProjectStage): string {
|
|
stageToAnchor(stage: ProjectStage): string {
|
|
|
const map: Record<ProjectStage, string> = {
|
|
const map: Record<ProjectStage, string> = {
|
|
|
- '订单创建': 'order',
|
|
|
|
|
|
|
+ '订单分配': 'order',
|
|
|
'需求沟通': 'requirements-talk',
|
|
'需求沟通': 'requirements-talk',
|
|
|
'方案确认': 'proposal-confirm',
|
|
'方案确认': 'proposal-confirm',
|
|
|
'建模': 'modeling',
|
|
'建模': 'modeling',
|
|
@@ -2208,7 +2233,7 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 订单创建阶段:客户信息(迁移自客服端"客户信息"卡片)
|
|
|
|
|
|
|
+ // 订单分配阶段:客户信息(迁移自客服端"客户信息"卡片)
|
|
|
orderCreationMethod: 'miniprogram' | 'manual' = 'miniprogram';
|
|
orderCreationMethod: 'miniprogram' | 'manual' = 'miniprogram';
|
|
|
isSyncing: boolean = false;
|
|
isSyncing: boolean = false;
|
|
|
orderTime: string = '';
|
|
orderTime: string = '';
|
|
@@ -2390,6 +2415,13 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
console.log('预览文件:', file.name);
|
|
console.log('预览文件:', file.name);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 处理参考图更新事件
|
|
|
|
|
+ onReferenceImagesUpdated(images: any[]): void {
|
|
|
|
|
+ console.log('参考图已更新:', images);
|
|
|
|
|
+ // 这里可以实现保存到后端的逻辑
|
|
|
|
|
+ // 也可以触发项目状态的更新
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 同步需求关键信息到客户信息卡片
|
|
// 同步需求关键信息到客户信息卡片
|
|
|
syncRequirementKeyInfo(requirementData: any): void {
|
|
syncRequirementKeyInfo(requirementData: any): void {
|
|
|
if (requirementData) {
|
|
if (requirementData) {
|
|
@@ -2557,7 +2589,7 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const stageOrder = [
|
|
const stageOrder = [
|
|
|
- '订单创建', '需求沟通', '方案确认', '建模', '软装',
|
|
|
|
|
|
|
+ '订单分配', '需求沟通', '方案确认', '建模', '软装',
|
|
|
'渲染', '尾款结算', '客户评价', '投诉处理'
|
|
'渲染', '尾款结算', '客户评价', '投诉处理'
|
|
|
];
|
|
];
|
|
|
|
|
|
|
@@ -2649,12 +2681,12 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
getProjectStatusText(): string {
|
|
getProjectStatusText(): string {
|
|
|
const current = (this.currentStage || this.project?.currentStage) as ProjectStage | undefined;
|
|
const current = (this.currentStage || this.project?.currentStage) as ProjectStage | undefined;
|
|
|
|
|
|
|
|
- if (!current || current === '订单创建') {
|
|
|
|
|
|
|
+ if (!current || current === '订单分配') {
|
|
|
return '待开始';
|
|
return '待开始';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 检查是否已完成所有阶段
|
|
// 检查是否已完成所有阶段
|
|
|
- const allStages: ProjectStage[] = ['订单创建', '需求沟通', '方案确认', '建模', '软装', '渲染', '尾款结算', '客户评价', '投诉处理'];
|
|
|
|
|
|
|
+ const allStages: ProjectStage[] = ['订单分配', '需求沟通', '方案确认', '建模', '软装', '渲染', '尾款结算', '客户评价', '投诉处理'];
|
|
|
const currentIndex = allStages.indexOf(current);
|
|
const currentIndex = allStages.indexOf(current);
|
|
|
|
|
|
|
|
if (currentIndex === allStages.length - 1) {
|
|
if (currentIndex === allStages.length - 1) {
|
|
@@ -2668,8 +2700,8 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
getCurrentStageText(): string {
|
|
getCurrentStageText(): string {
|
|
|
const current = (this.currentStage || this.project?.currentStage) as ProjectStage | undefined;
|
|
const current = (this.currentStage || this.project?.currentStage) as ProjectStage | undefined;
|
|
|
|
|
|
|
|
- if (!current || current === '订单创建') {
|
|
|
|
|
- return '订单创建阶段';
|
|
|
|
|
|
|
+ if (!current || current === '订单分配') {
|
|
|
|
|
+ return '订单分配阶段';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return `${current}阶段`;
|
|
return `${current}阶段`;
|
|
@@ -2685,7 +2717,7 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
|
|
|
|
|
// 定义所有阶段及其权重
|
|
// 定义所有阶段及其权重
|
|
|
const stageWeights: Record<ProjectStage, number> = {
|
|
const stageWeights: Record<ProjectStage, number> = {
|
|
|
- '订单创建': 5,
|
|
|
|
|
|
|
+ '订单分配': 5,
|
|
|
'需求沟通': 15,
|
|
'需求沟通': 15,
|
|
|
'方案确认': 25,
|
|
'方案确认': 25,
|
|
|
'建模': 40,
|
|
'建模': 40,
|
|
@@ -2841,12 +2873,12 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 处理咨询订单表单提交
|
|
// 处理咨询订单表单提交
|
|
|
- // 存储订单创建时的客户信息和需求信息
|
|
|
|
|
|
|
+ // 存储订单分配时的客户信息和需求信息
|
|
|
|
|
|
|
|
onConsultationOrderSubmit(formData: any): void {
|
|
onConsultationOrderSubmit(formData: any): void {
|
|
|
console.log('咨询订单表单提交:', formData);
|
|
console.log('咨询订单表单提交:', formData);
|
|
|
|
|
|
|
|
- // 保存订单创建数据
|
|
|
|
|
|
|
+ // 保存订单分配数据
|
|
|
this.orderCreationData = formData;
|
|
this.orderCreationData = formData;
|
|
|
|
|
|
|
|
// 更新projectData以便传递给子组件(集成报价与指派信息)
|
|
// 更新projectData以便传递给子组件(集成报价与指派信息)
|
|
@@ -2968,7 +3000,7 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
// 进入下一个阶段:需求沟通
|
|
// 进入下一个阶段:需求沟通
|
|
|
this.updateProjectStage('需求沟通');
|
|
this.updateProjectStage('需求沟通');
|
|
|
this.expandedStages['需求沟通'] = true;
|
|
this.expandedStages['需求沟通'] = true;
|
|
|
- this.expandedStages['订单创建'] = false;
|
|
|
|
|
|
|
+ this.expandedStages['订单分配'] = false;
|
|
|
|
|
|
|
|
// 显示成功消息
|
|
// 显示成功消息
|
|
|
alert('团队分配成功!已进入需求沟通阶段');
|
|
alert('团队分配成功!已进入需求沟通阶段');
|
|
@@ -2990,9 +3022,9 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
this.project.currentStage = '需求沟通';
|
|
this.project.currentStage = '需求沟通';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 展开需求沟通阶段,收起订单创建阶段
|
|
|
|
|
|
|
+ // 展开需求沟通阶段,收起订单分配阶段
|
|
|
this.expandedStages['需求沟通'] = true;
|
|
this.expandedStages['需求沟通'] = true;
|
|
|
- this.expandedStages['订单创建'] = false;
|
|
|
|
|
|
|
+ this.expandedStages['订单分配'] = false;
|
|
|
|
|
|
|
|
// 自动展开确认需求板块
|
|
// 自动展开确认需求板块
|
|
|
this.expandedSection = 'requirements';
|
|
this.expandedSection = 'requirements';
|
|
@@ -3721,7 +3753,7 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
sopStagesData: any[] = [
|
|
sopStagesData: any[] = [
|
|
|
- { name: '订单创建', plannedDuration: 1, actualDuration: 1, score: 95, status: 'completed', statusText: '已完成', isDelayed: false, issues: [] },
|
|
|
|
|
|
|
+ { name: '订单分配', plannedDuration: 1, actualDuration: 1, score: 95, status: 'completed', statusText: '已完成', isDelayed: false, issues: [] },
|
|
|
{ name: '需求沟通', plannedDuration: 3, actualDuration: 4, score: 75, status: 'completed', statusText: '已完成', isDelayed: true, issues: ['沟通次数超标'] },
|
|
{ name: '需求沟通', plannedDuration: 3, actualDuration: 4, score: 75, status: 'completed', statusText: '已完成', isDelayed: true, issues: ['沟通次数超标'] },
|
|
|
{ name: '方案确认', plannedDuration: 2, actualDuration: 2, score: 90, status: 'completed', statusText: '已完成', isDelayed: false, issues: [] },
|
|
{ name: '方案确认', plannedDuration: 2, actualDuration: 2, score: 90, status: 'completed', statusText: '已完成', isDelayed: false, issues: [] },
|
|
|
{ name: '建模', plannedDuration: 4, actualDuration: 5, score: 80, status: 'completed', statusText: '已完成', isDelayed: true, issues: ['细节调整耗时'] },
|
|
{ name: '建模', plannedDuration: 4, actualDuration: 5, score: 80, status: 'completed', statusText: '已完成', isDelayed: true, issues: ['细节调整耗时'] },
|
|
@@ -4092,6 +4124,9 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
startPanoramicSynthesis(): void {
|
|
startPanoramicSynthesis(): void {
|
|
|
console.log('🎨 启动全景图合成...');
|
|
console.log('🎨 启动全景图合成...');
|
|
|
|
|
|
|
|
|
|
+ // 显示提示信息
|
|
|
|
|
+ alert('📸 请选择需要合成全景图的图片\n\n提示:\n1. 建议选择同一空间的多个角度照片\n2. 图片文件名可以包含空间名称(如:客厅-角度1.jpg)\n3. 系统会自动识别并分类');
|
|
|
|
|
+
|
|
|
// 打开文件选择对话框,支持多文件选择
|
|
// 打开文件选择对话框,支持多文件选择
|
|
|
const fileInput = document.createElement('input');
|
|
const fileInput = document.createElement('input');
|
|
|
fileInput.type = 'file';
|
|
fileInput.type = 'file';
|
|
@@ -4240,19 +4275,19 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
|
|
|
|
|
// 查看全景图画廊
|
|
// 查看全景图画廊
|
|
|
viewPanoramicGallery(): void {
|
|
viewPanoramicGallery(): void {
|
|
|
- console.log('打开全景图画廊');
|
|
|
|
|
|
|
+ console.log('📁 打开全景图画廊');
|
|
|
|
|
|
|
|
if (this.panoramicSyntheses.length === 0) {
|
|
if (this.panoramicSyntheses.length === 0) {
|
|
|
- alert('暂无全景图记录');
|
|
|
|
|
|
|
+ alert('📁 全景图画廊\n\n暂无全景图记录,请先进行全景图合成。');
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 显示全景图列表
|
|
|
|
|
- const galleryInfo = this.panoramicSyntheses.map((s, i) =>
|
|
|
|
|
- `${i + 1}. ${s.projectName} - ${s.status === 'completed' ? '已完成' : '处理中'} (${s.spaces.length}个空间)`
|
|
|
|
|
|
|
+ // 显示全景图列表提示
|
|
|
|
|
+ const galleryInfo = this.panoramicSyntheses.map((item, index) =>
|
|
|
|
|
+ `${index + 1}. ${item.projectName} - ${item.status === 'completed' ? '✅ 已完成' : '⏳ 处理中'} (${item.spaces?.length || 0}个空间)`
|
|
|
).join('\n');
|
|
).join('\n');
|
|
|
|
|
|
|
|
- alert(`全景图画廊\n\n${galleryInfo}\n\n点击查看详情功能开发中...`);
|
|
|
|
|
|
|
+ alert(`📁 全景图画廊(共${this.panoramicSyntheses.length}个)\n\n${galleryInfo}\n\n提示:点击列表中的全景图可查看详情或下载`);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 复制全景图链接
|
|
// 复制全景图链接
|
|
@@ -4368,6 +4403,9 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
createComplaintManually(): void {
|
|
createComplaintManually(): void {
|
|
|
console.log('📝 手动创建投诉');
|
|
console.log('📝 手动创建投诉');
|
|
|
|
|
|
|
|
|
|
+ // 显示创建投诉表单提示
|
|
|
|
|
+ alert('📝 创建投诉记录\n\n即将打开投诉创建表单,请填写以下信息:\n• 投诉环节\n• 核心问题\n• 客户反馈\n• 严重程度');
|
|
|
|
|
+
|
|
|
// 弹出创建投诉表单
|
|
// 弹出创建投诉表单
|
|
|
const complaintReason = prompt('请输入投诉原因:');
|
|
const complaintReason = prompt('请输入投诉原因:');
|
|
|
if (!complaintReason || complaintReason.trim() === '') return;
|
|
if (!complaintReason || complaintReason.trim() === '') return;
|
|
@@ -4452,21 +4490,24 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
console.log('⚙️ 设置关键词监控');
|
|
console.log('⚙️ 设置关键词监控');
|
|
|
|
|
|
|
|
if (this.isKeywordMonitoringActive) {
|
|
if (this.isKeywordMonitoringActive) {
|
|
|
- const confirmStop = confirm('关键词监控已激活,是否停止监控?');
|
|
|
|
|
|
|
+ const confirmStop = confirm('⚙️ 关键词监控管理\n\n状态:✅ 已激活\n监控关键词:' + this.complaintKeywords.join('、') + '\n\n是否停止监控?');
|
|
|
if (confirmStop) {
|
|
if (confirmStop) {
|
|
|
this.isKeywordMonitoringActive = false;
|
|
this.isKeywordMonitoringActive = false;
|
|
|
- alert('✅ 关键词监控已停止');
|
|
|
|
|
|
|
+ alert('⏸️ 关键词监控已停止\n\n系统将不再自动抓取企业微信群中的投诉关键词');
|
|
|
}
|
|
}
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 显示当前监控关键词
|
|
|
|
|
|
|
+ // 显示设置说明和当前关键词
|
|
|
|
|
+ alert('⚙️ 关键词监控功能\n\n功能说明:\n• 自动监测企业微信群消息\n• 识别投诉相关关键词\n• 自动创建投诉记录并标注\n• 实时通知相关处理人员\n\n当前监控关键词:\n' + this.complaintKeywords.join('、'));
|
|
|
|
|
+
|
|
|
const currentKeywords = this.complaintKeywords.join('、');
|
|
const currentKeywords = this.complaintKeywords.join('、');
|
|
|
- const newKeywords = prompt(`当前监控关键词:\n\n${currentKeywords}\n\n请输入要添加的关键词(多个关键词用逗号分隔):`);
|
|
|
|
|
|
|
+ const newKeywords = prompt(`当前监控关键词:\n${currentKeywords}\n\n请输入要添加的关键词(多个关键词用逗号分隔):`);
|
|
|
|
|
|
|
|
if (newKeywords && newKeywords.trim()) {
|
|
if (newKeywords && newKeywords.trim()) {
|
|
|
const keywords = newKeywords.split(/[,,、]/).map(k => k.trim()).filter(k => k);
|
|
const keywords = newKeywords.split(/[,,、]/).map(k => k.trim()).filter(k => k);
|
|
|
this.complaintKeywords = [...new Set([...this.complaintKeywords, ...keywords])];
|
|
this.complaintKeywords = [...new Set([...this.complaintKeywords, ...keywords])];
|
|
|
|
|
+ alert(`✅ 关键词已更新\n\n新增关键词:${keywords.join('、')}\n\n全部监控关键词:\n${this.complaintKeywords.join('、')}`);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 激活监控
|
|
// 激活监控
|
|
@@ -4688,7 +4729,7 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
|
|
|
|
|
// 初始化表单
|
|
// 初始化表单
|
|
|
initializeForms(): void {
|
|
initializeForms(): void {
|
|
|
- // 初始化订单创建表单(必填项)
|
|
|
|
|
|
|
+ // 初始化订单分配表单(必填项)
|
|
|
this.orderCreationForm = this.fb.group({
|
|
this.orderCreationForm = this.fb.group({
|
|
|
orderAmount: ['', [Validators.required, Validators.min(0)]],
|
|
orderAmount: ['', [Validators.required, Validators.min(0)]],
|
|
|
smallImageDeliveryTime: ['', Validators.required],
|
|
smallImageDeliveryTime: ['', Validators.required],
|
|
@@ -4708,12 +4749,12 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 检查是否可以创建订单
|
|
|
|
|
|
|
+ // 检查是否可以分配订单
|
|
|
canCreateOrder(): boolean {
|
|
canCreateOrder(): boolean {
|
|
|
return this.orderCreationForm ? this.orderCreationForm.valid : false;
|
|
return this.orderCreationForm ? this.orderCreationForm.valid : false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 创建订单
|
|
|
|
|
|
|
+ // 分配订单
|
|
|
createOrder(): void {
|
|
createOrder(): void {
|
|
|
if (!this.canCreateOrder()) {
|
|
if (!this.canCreateOrder()) {
|
|
|
// 标记所有字段为已触摸,以显示验证错误
|
|
// 标记所有字段为已触摸,以显示验证错误
|
|
@@ -4729,14 +4770,14 @@ export class ProjectDetail implements OnInit, OnDestroy {
|
|
|
designerAssignment: this.designerAssignmentData
|
|
designerAssignment: this.designerAssignmentData
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- console.log('创建订单:', orderData);
|
|
|
|
|
|
|
+ console.log('分配订单:', orderData);
|
|
|
|
|
|
|
|
- // 这里应该调用API创建订单
|
|
|
|
|
|
|
+ // 这里应该调用API分配订单
|
|
|
// 模拟API调用
|
|
// 模拟API调用
|
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
|
- alert('订单创建成功!');
|
|
|
|
|
- // 订单创建成功后自动切换到下一环节
|
|
|
|
|
- this.advanceToNextStage('订单创建');
|
|
|
|
|
|
|
+ alert('订单分配成功!');
|
|
|
|
|
+ // 订单分配成功后自动切换到下一环节
|
|
|
|
|
+ this.advanceToNextStage('订单分配');
|
|
|
}, 500);
|
|
}, 500);
|
|
|
}
|
|
}
|
|
|
|
|
|