123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- import { Component, signal, Inject } from '@angular/core';
- import { CommonModule } from '@angular/common';
- import { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
- import { RouterModule } from '@angular/router';
- import { ProjectService } from '../../../services/project.service';
- import { MatChipInputEvent } from '@angular/material/chips';
- import { COMMA, ENTER } from '@angular/cdk/keycodes';
- import { MatChipsModule } from '@angular/material/chips';
- import { MatIconModule } from '@angular/material/icon';
- import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
- import { MatDialog, MatDialogModule, MAT_DIALOG_DATA } from '@angular/material/dialog';
- import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
- import { ProjectGroupDialog } from './project-group-dialog.component';
- // 定义客户信息接口
- interface Customer {
- id: string;
- name: string;
- phone: string;
- wechat?: string;
- avatar?: string;
- customerType?: string; // 新客户/老客户/VIP客户
- source?: string; // 来源渠道
- remark?: string;
- // 客户标签信息
- demandType?: string;
- preferenceTags?: string[];
- followUpStatus?: string;
- }
- // 定义需求信息接口
- interface Requirement {
- style: string;
- budget: string;
- area: number;
- houseType: string;
- floor: number;
- decorationType: string;
- preferredDesigner?: string;
- specialRequirements?: string;
- referenceCases?: string[];
- }
- // 标签选项定义
- const DEMAND_TYPES = [
- { value: 'price', label: '价格敏感' },
- { value: 'quality', label: '质量敏感' },
- { value: 'comprehensive', label: '综合要求' }
- ];
- const FOLLOW_UP_STATUS = [
- { value: 'quotation', label: '待报价' },
- { value: 'confirm', label: '待确认需求' },
- { value: 'lost', label: '已失联' }
- ];
- // 预设的偏好标签选项
- const PREFERENCE_TAG_OPTIONS = [
- // 颜色偏好
- '柔和色系', '明亮色系', '深色系', '中性色系',
- // 材质偏好
- '环保材料', '实木', '大理石', '瓷砖', '地板', '墙纸',
- // 风格偏好
- '现代简约', '北欧风格', '中式风格', '美式风格', '工业风',
- // 其他偏好
- '智能家电', '收纳空间', '开放式厨房', '大窗户'
- ];
- @Component({
- selector: 'app-consultation-order',
- standalone: true,
- imports: [
- CommonModule,
- FormsModule,
- ReactiveFormsModule,
- RouterModule,
- MatChipsModule,
- MatIconModule,
- MatSnackBarModule,
- MatDialogModule,
- MatProgressSpinnerModule
- ],
- templateUrl: './consultation-order.html',
- styleUrls: ['./consultation-order.scss', '../customer-service-styles.scss']
- })
- export class ConsultationOrder {
- // 搜索客户关键词
- searchKeyword = signal('');
- // 搜索结果列表
- searchResults = signal<Customer[]>([]);
- // 选中的客户
- selectedCustomer = signal<Customer | null>(null);
- // 报价范围
- estimatedPriceRange = signal<string>('');
- // 匹配的案例
- matchedCases = signal<any[]>([]);
- // 表单提交状态
- isSubmitting = signal(false);
- // 成功提示显示状态
- showSuccessMessage = signal(false);
- // 需求表单
- requirementForm: FormGroup;
- // 客户表单
- customerForm: FormGroup;
- // 样式选项
- styleOptions = [
- '现代简约', '北欧风', '工业风', '新中式', '法式轻奢', '日式', '美式', '混搭'
- ];
-
- // 户型选项
- houseTypeOptions = [
- '一室一厅', '两室一厅', '两室两厅', '三室一厅', '三室两厅', '四室两厅', '复式', '别墅', '其他'
- ];
-
- // 装修类型选项
- decorationTypeOptions = [
- '全包', '半包', '清包', '旧房翻新', '局部改造'
- ];
- // 标签系统
- demandTypes = DEMAND_TYPES;
- followUpStatus = FOLLOW_UP_STATUS;
- preferenceTagOptions = PREFERENCE_TAG_OPTIONS;
- addOnBlur = true;
- readonly separatorKeysCodes = [ENTER, COMMA] as const;
- preferenceTags: string[] = [];
- constructor(
- private fb: FormBuilder,
- private projectService: ProjectService,
- private snackBar: MatSnackBar,
- private dialog: MatDialog
- ) {
- // 初始化需求表单
- this.requirementForm = this.fb.group({
- style: ['', Validators.required],
- budget: ['', Validators.required],
- area: ['', [Validators.required, Validators.min(1)]],
- houseType: ['', Validators.required],
- floor: ['', Validators.min(1)],
- decorationType: ['', Validators.required],
- preferredDesigner: [''],
- specialRequirements: [''],
- referenceCases: [[]]
- });
- // 初始化客户表单
- this.customerForm = this.fb.group({
- name: ['', Validators.required],
- phone: ['', [Validators.required, Validators.pattern(/^1[3-9]\d{9}$/)]],
- wechat: [''],
- customerType: ['新客户'],
- source: [''],
- remark: [''],
- demandType: [''],
- followUpStatus: ['']
- });
- // 监听表单值变化,自动计算报价和匹配案例
- this.requirementForm.valueChanges.subscribe(() => {
- this.calculateEstimatedPrice();
- this.matchCases();
- });
- }
- // 添加偏好标签
- addPreferenceTag(event: MatChipInputEvent): void {
- const value = (event.value || '').trim();
- // 添加标签,如果它不是空的,并且不在已有标签中
- if (value && !this.preferenceTags.includes(value)) {
- this.preferenceTags.push(value);
- }
- // 清空输入框
- if (event.input) {
- event.input.value = '';
- }
- }
- // 删除偏好标签
- removePreferenceTag(tag: string): void {
- const index = this.preferenceTags.indexOf(tag);
- if (index >= 0) {
- this.preferenceTags.splice(index, 1);
- }
- }
- // 从预设选项中添加标签
- addFromPreset(tag: string): void {
- if (!this.preferenceTags.includes(tag)) {
- this.preferenceTags.push(tag);
- }
- }
- // 搜索客户
- searchCustomer() {
- if (this.searchKeyword().length >= 2) {
- // 模拟搜索结果
- this.searchResults.set([
- {
- id: '1',
- name: '张先生',
- phone: '138****5678',
- customerType: '老客户',
- source: '官网咨询',
- avatar: "data:image/svg+xml,%3Csvg width='64' height='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' fill='%23E6E6E6'/%3E%3Ctext x='50%25' y='50%25' font-family='Arial' font-size='13.333333333333334' font-weight='bold' text-anchor='middle' fill='%23555555' dy='0.3em'%3EIMG%3C/text%3E%3C/svg%3E"
- },
- {
- id: '2',
- name: '李女士',
- phone: '139****1234',
- customerType: 'VIP客户',
- source: '推荐介绍',
- avatar: "data:image/svg+xml,%3Csvg width='65' height='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' fill='%23DCDCDC'/%3E%3Ctext x='50%25' y='50%25' font-family='Arial' font-size='13.333333333333334' font-weight='bold' text-anchor='middle' fill='%23555555' dy='0.3em'%3EIMG%3C/text%3E%3C/svg%3E"
- }
- ]);
- }
- }
- // 选择客户
- selectCustomer(customer: Customer) {
- this.selectedCustomer.set(customer);
- // 填充客户表单
- this.customerForm.patchValue({
- name: customer.name,
- phone: customer.phone,
- wechat: customer.wechat || '',
- customerType: customer.customerType || '新客户',
- source: customer.source || '',
- remark: customer.remark || ''
- });
- // 清空搜索结果
- this.searchResults.set([]);
- this.searchKeyword.set('');
- }
- // 清除选中的客户
- clearSelectedCustomer() {
- this.selectedCustomer.set(null);
- this.customerForm.reset({
- customerType: '新客户'
- });
- }
- // 计算预估报价
- calculateEstimatedPrice() {
- const { area, decorationType, style } = this.requirementForm.value;
- if (area && decorationType) {
- // 模拟报价计算逻辑
- let basePrice = 0;
- switch (decorationType) {
- case '全包':
- basePrice = 1800;
- break;
- case '半包':
- basePrice = 1200;
- break;
- case '清包':
- basePrice = 800;
- break;
- case '旧房翻新':
- basePrice = 2000;
- break;
- case '局部改造':
- basePrice = 1500;
- break;
- default:
- basePrice = 1200;
- break;
- }
- // 风格加价
- const stylePremium = ['法式轻奢', '新中式', '日式'].includes(style) ? 0.2 : 0;
- const totalPrice = area * basePrice * (1 + stylePremium);
- const lowerBound = Math.floor(totalPrice * 0.9);
- const upperBound = Math.ceil(totalPrice * 1.1);
-
- this.estimatedPriceRange.set(
- `¥${lowerBound.toLocaleString()} - ¥${upperBound.toLocaleString()}`
- );
- }
- }
- // 匹配案例
- matchCases() {
- const { style, houseType, area } = this.requirementForm.value;
- if (style && houseType && area) {
- // 模拟匹配案例
- this.matchedCases.set([
- {
- id: '101',
- name: `${style}风格 ${houseType}设计`,
- imageUrl: `https://picsum.photos/id/${30 + Math.floor(Math.random() * 10)}/300/200`,
- designer: '王设计师',
- area: area + '㎡',
- similarity: 92
- },
- {
- id: '102',
- name: `${houseType} ${style}案例展示`,
- imageUrl: `https://picsum.photos/id/${40 + Math.floor(Math.random() * 10)}/300/200`,
- designer: '张设计师',
- area: (area + 10) + '㎡',
- similarity: 85
- }
- ]);
- }
- }
- // 选择参考案例
- selectReferenceCase(caseItem: any) {
- const currentCases = this.requirementForm.get('referenceCases')?.value || [];
- if (!currentCases.includes(caseItem.id)) {
- this.requirementForm.patchValue({
- referenceCases: [...currentCases, caseItem.id]
- });
- }
- }
- // 移除参考案例
- removeReferenceCase(caseId: string) {
- const currentCases = this.requirementForm.get('referenceCases')?.value || [];
- this.requirementForm.patchValue({
- referenceCases: currentCases.filter((id: string) => id !== caseId)
- });
- }
- // 提交表单
- submitForm() {
- if (this.requirementForm.valid && this.customerForm.valid) {
- this.isSubmitting.set(true);
-
- const formData = {
- customerInfo: this.customerForm.value,
- requirementInfo: this.requirementForm.value,
- estimatedPriceRange: this.estimatedPriceRange(),
- createdAt: new Date()
- };
- // 模拟提交请求
- setTimeout(() => {
- console.log('提交的表单数据:', formData);
- this.isSubmitting.set(false);
- this.showSuccessMessage.set(true);
-
- // 3秒后隐藏成功提示
- setTimeout(() => {
- this.showSuccessMessage.set(false);
- }, 3000);
- }, 1500);
- }
- }
- // 创建项目
- createProject() {
- if (!this.selectedCustomer()) {
- this.snackBar.open('请先选择客户', '关闭', { duration: 3000 });
- return;
- }
- if (this.requirementForm.invalid) {
- this.snackBar.open('请完善需求信息', '关闭', { duration: 3000 });
- return;
- }
- const selectedCustomer = this.selectedCustomer()!;
- const projectData = {
- customerId: selectedCustomer.id,
- customerName: selectedCustomer.name,
- requirement: this.requirementForm.value,
- referenceCases: this.requirementForm.get('referenceCases')?.value || [],
- tags: {
- demandType: this.customerForm.get('demandType')?.value,
- preferenceTags: this.preferenceTags,
- followUpStatus: this.customerForm.get('followUpStatus')?.value
- }
- };
- this.projectService.createProject(projectData).subscribe(
- (response: any) => {
- this.snackBar.open('项目创建成功', '关闭', { duration: 3000 });
- },
- (error: any) => {
- this.snackBar.open('项目创建失败,请重试', '关闭', { duration: 3000 });
- }
- );
- }
- /**
- * 创建项目群
- */
- createProjectGroup() {
- // 先检查是否选择了客户
- if (!this.selectedCustomer()) {
- this.snackBar.open('请先选择客户', '确定', { duration: 2000 });
- return;
- }
-
- // 显示弹窗
- this.dialog.open(ProjectGroupDialog, {
- width: '500px',
- data: {
- selectedCustomer: this.selectedCustomer(),
- demandType: this.customerForm.get('demandType')?.value,
- preferenceTags: this.preferenceTags,
- followUpStatus: this.customerForm.get('followUpStatus')?.value
- }
- }).afterClosed().subscribe(result => {
- if (result && result.confirm) {
- const tags = {
- demandType: result.demandType,
- preferenceTags: result.preferenceTags,
- followUpStatus: result.followUpStatus
- };
- this.isSubmitting.set(true);
- this.projectService.createProjectGroup({
- customerId: result.customerId,
- customerName: result.customerName,
- tags
- }).subscribe(
- (response: any) => {
- if (response.success) {
- this.snackBar.open(`项目群创建成功,群ID: ${response.groupId}`, '确定', { duration: 3000 });
- } else {
- this.snackBar.open('项目群创建失败,请稍后重试', '确定', { duration: 2000 });
- }
- this.isSubmitting.set(false);
- },
- (error: any) => {
- this.snackBar.open('创建项目群时出错,请稍后重试', '确定', { duration: 2000 });
- this.isSubmitting.set(false);
- }
- );
- }
- });
- }
- }
|