consultation-order.ts 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. import { Component, signal, Inject, Output, EventEmitter } from '@angular/core';
  2. import { CommonModule } from '@angular/common';
  3. import { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
  4. import { Router, RouterModule } from '@angular/router';
  5. import { ProjectService } from '../../../services/project.service';
  6. import { MatChipInputEvent } from '@angular/material/chips';
  7. import { COMMA, ENTER } from '@angular/cdk/keycodes';
  8. import { MatChipsModule } from '@angular/material/chips';
  9. import { MatIconModule } from '@angular/material/icon';
  10. import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
  11. import { MatDialog, MatDialogModule, MAT_DIALOG_DATA } from '@angular/material/dialog';
  12. import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
  13. import { ProjectGroupDialog } from './project-group-dialog.component';
  14. // 定义客户信息接口
  15. interface Customer {
  16. id: string;
  17. name: string;
  18. phone: string;
  19. wechat?: string;
  20. avatar?: string;
  21. customerType?: string; // 新客户/老客户/VIP客户
  22. source?: string; // 来源渠道
  23. remark?: string;
  24. // 客户标签信息
  25. demandType?: string;
  26. preferenceTags?: string[];
  27. followUpStatus?: string;
  28. }
  29. // 定义需求信息接口
  30. interface Requirement {
  31. style: string;
  32. budget: string;
  33. area: number;
  34. houseType: string;
  35. floor: number;
  36. decorationType: string;
  37. preferredDesigner?: string;
  38. specialRequirements?: string;
  39. referenceCases?: string[];
  40. }
  41. // 标签选项定义
  42. const DEMAND_TYPES = [
  43. { value: 'price', label: '价格敏感' },
  44. { value: 'quality', label: '质量敏感' },
  45. { value: 'comprehensive', label: '综合要求' }
  46. ];
  47. const FOLLOW_UP_STATUS = [
  48. { value: 'quotation', label: '待报价' },
  49. { value: 'confirm', label: '待确认需求' },
  50. { value: 'lost', label: '已失联' }
  51. ];
  52. // 预设的偏好标签选项
  53. const PREFERENCE_TAG_OPTIONS = [
  54. // 颜色偏好
  55. '柔和色系', '明亮色系', '深色系', '中性色系',
  56. // 材质偏好
  57. '环保材料', '实木', '大理石', '瓷砖', '地板', '墙纸',
  58. // 风格偏好
  59. '现代简约', '北欧风格', '中式风格', '美式风格', '工业风',
  60. // 其他偏好
  61. '智能家电', '收纳空间', '开放式厨房', '大窗户'
  62. ];
  63. @Component({
  64. selector: 'app-consultation-order',
  65. standalone: true,
  66. imports: [
  67. CommonModule,
  68. FormsModule,
  69. ReactiveFormsModule,
  70. RouterModule,
  71. MatChipsModule,
  72. MatIconModule,
  73. MatSnackBarModule,
  74. MatDialogModule,
  75. MatProgressSpinnerModule
  76. ],
  77. templateUrl: './consultation-order.html',
  78. styleUrls: ['./consultation-order.scss', '../customer-service-styles.scss']
  79. })
  80. export class ConsultationOrder {
  81. // 搜索客户关键词
  82. searchKeyword = signal('');
  83. // 搜索结果列表
  84. searchResults = signal<Customer[]>([]);
  85. // 选中的客户
  86. selectedCustomer = signal<Customer | null>(null);
  87. // 报价范围
  88. estimatedPriceRange = signal<string>('');
  89. // 匹配的案例
  90. matchedCases = signal<any[]>([]);
  91. // 表单提交状态
  92. isSubmitting = signal(false);
  93. // 成功提示显示状态
  94. showSuccessMessage = signal(false);
  95. // 下单时间(自动生成)
  96. orderTime = signal<string>('');
  97. // 项目需求卡片展开状态
  98. isRequirementCardExpanded = signal(false);
  99. // 订单创建成功事件
  100. @Output() orderCreated = new EventEmitter<any>();
  101. // 需求表单
  102. requirementForm: FormGroup;
  103. // 客户表单
  104. customerForm: FormGroup;
  105. // 项目配置表单
  106. projectForm: FormGroup;
  107. // 样式选项
  108. styleOptions = [
  109. '现代简约', '北欧风', '工业风', '新中式', '法式轻奢', '日式', '美式', '混搭'
  110. ];
  111. // 装修风格选项(用于项目配置)
  112. decorationStyles = [
  113. { value: 'modern', label: '现代简约' },
  114. { value: 'nordic', label: '北欧风' },
  115. { value: 'industrial', label: '工业风' },
  116. { value: 'chinese', label: '新中式' },
  117. { value: 'french', label: '法式轻奢' },
  118. { value: 'japanese', label: '日式' },
  119. { value: 'american', label: '美式' },
  120. { value: 'mixed', label: '混搭' }
  121. ];
  122. // 项目小组选项
  123. projectGroups = [
  124. { value: 'design1', label: '设计一组' },
  125. { value: 'design2', label: '设计二组' },
  126. { value: 'design3', label: '设计三组' },
  127. { value: 'premium', label: '高端定制组' },
  128. { value: 'soft', label: '软装设计组' }
  129. ];
  130. // 项目小组选项(兼容性)
  131. projectGroupOptions = [
  132. '设计一组', '设计二组', '设计三组', '高端定制组', '软装设计组'
  133. ];
  134. // 标签系统
  135. demandTypes = DEMAND_TYPES;
  136. followUpStatus = FOLLOW_UP_STATUS;
  137. preferenceTagOptions = PREFERENCE_TAG_OPTIONS;
  138. addOnBlur = true;
  139. readonly separatorKeysCodes = [ENTER, COMMA] as const;
  140. preferenceTags: string[] = [];
  141. constructor(
  142. private fb: FormBuilder,
  143. private projectService: ProjectService,
  144. private snackBar: MatSnackBar,
  145. private dialog: MatDialog,
  146. private router: Router
  147. ) {
  148. // 初始化需求表单(保留兼容性)
  149. this.requirementForm = this.fb.group({
  150. decorationType: ['', Validators.required], // 装修类型(必填)
  151. downPayment: ['', [Validators.required, Validators.min(0)]], // 首付款(必填)
  152. firstDraftDate: ['', Validators.required], // 首稿时间(必填)
  153. style: [''], // 装修风格(选填)
  154. projectGroup: [''], // 项目小组(选填)
  155. budget: ['', Validators.required],
  156. area: ['', [Validators.required, Validators.min(1)]],
  157. houseType: [''], // 改为非必填
  158. floor: ['', Validators.min(1)],
  159. preferredDesigner: [''],
  160. specialRequirements: [''],
  161. referenceCases: [[]],
  162. priceDetails: [''] // 价格明细
  163. });
  164. // 初始化客户表单
  165. this.customerForm = this.fb.group({
  166. name: ['', Validators.required],
  167. phone: ['', [Validators.required, Validators.pattern(/^1[3-9]\d{9}$/)]],
  168. wechat: [''],
  169. customerType: ['新客户'],
  170. source: [''],
  171. remark: [''],
  172. demandType: [''],
  173. followUpStatus: ['']
  174. });
  175. // 初始化项目配置表单
  176. this.projectForm = this.fb.group({
  177. style: ['', Validators.required], // 风格选择
  178. projectGroup: ['', Validators.required], // 项目组匹配
  179. downPaymentSetting: ['', Validators.required], // 首付款设置
  180. downPaymentAmount: ['', [Validators.required, Validators.min(0)]], // 首付款填写
  181. firstDraftConfirm: [false, Validators.requiredTrue], // 首稿时间确认
  182. firstDraftDate: ['', Validators.required] // 首稿时间设置
  183. });
  184. // 自动生成下单时间
  185. this.orderTime.set(new Date().toLocaleString('zh-CN', {
  186. year: 'numeric',
  187. month: '2-digit',
  188. day: '2-digit',
  189. hour: '2-digit',
  190. minute: '2-digit',
  191. second: '2-digit'
  192. }));
  193. // 监听表单值变化,自动计算报价和匹配案例
  194. this.requirementForm.valueChanges.subscribe(() => {
  195. this.calculateEstimatedPrice();
  196. this.matchCases();
  197. });
  198. }
  199. // 添加偏好标签
  200. addPreferenceTag(event: MatChipInputEvent): void {
  201. const value = (event.value || '').trim();
  202. // 添加标签,如果它不是空的,并且不在已有标签中
  203. if (value && !this.preferenceTags.includes(value)) {
  204. this.preferenceTags.push(value);
  205. }
  206. // 清空输入框
  207. if (event.input) {
  208. event.input.value = '';
  209. }
  210. }
  211. // 删除偏好标签
  212. removePreferenceTag(tag: string): void {
  213. const index = this.preferenceTags.indexOf(tag);
  214. if (index >= 0) {
  215. this.preferenceTags.splice(index, 1);
  216. }
  217. }
  218. // 从预设选项中添加标签
  219. addFromPreset(tag: string): void {
  220. if (!this.preferenceTags.includes(tag)) {
  221. this.preferenceTags.push(tag);
  222. }
  223. }
  224. // 搜索客户
  225. searchCustomer() {
  226. if (this.searchKeyword().length >= 2) {
  227. // 模拟搜索结果
  228. this.searchResults.set([
  229. {
  230. id: '1',
  231. name: '张先生',
  232. phone: '138****5678',
  233. customerType: '老客户',
  234. source: '官网咨询',
  235. 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"
  236. },
  237. {
  238. id: '2',
  239. name: '李女士',
  240. phone: '139****1234',
  241. customerType: 'VIP客户',
  242. source: '推荐介绍',
  243. 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"
  244. }
  245. ]);
  246. }
  247. }
  248. // 选择客户
  249. selectCustomer(customer: Customer) {
  250. this.selectedCustomer.set(customer);
  251. // 填充客户表单
  252. this.customerForm.patchValue({
  253. name: customer.name,
  254. phone: customer.phone,
  255. wechat: customer.wechat || '',
  256. customerType: customer.customerType || '新客户',
  257. source: customer.source || '',
  258. remark: customer.remark || ''
  259. });
  260. // 如果是老客户,自动填充历史信息
  261. if (customer.customerType === '老客户' || customer.customerType === 'VIP客户') {
  262. this.loadCustomerHistory(customer.id);
  263. }
  264. // 清空搜索结果
  265. this.searchResults.set([]);
  266. this.searchKeyword.set('');
  267. }
  268. // 清除选中的客户
  269. clearSelectedCustomer() {
  270. this.selectedCustomer.set(null);
  271. this.customerForm.reset({
  272. customerType: '新客户'
  273. });
  274. }
  275. // 计算预估报价
  276. calculateEstimatedPrice() {
  277. const { area, decorationType, style } = this.requirementForm.value;
  278. if (area && decorationType) {
  279. // 模拟报价计算逻辑
  280. let basePrice = 0;
  281. switch (decorationType) {
  282. case '全包':
  283. basePrice = 1800;
  284. break;
  285. case '半包':
  286. basePrice = 1200;
  287. break;
  288. case '清包':
  289. basePrice = 800;
  290. break;
  291. case '旧房翻新':
  292. basePrice = 2000;
  293. break;
  294. case '局部改造':
  295. basePrice = 1500;
  296. break;
  297. default:
  298. basePrice = 1200;
  299. break;
  300. }
  301. // 风格加价
  302. const stylePremium = ['法式轻奢', '新中式', '日式'].includes(style) ? 0.2 : 0;
  303. const totalPrice = area * basePrice * (1 + stylePremium);
  304. const lowerBound = Math.floor(totalPrice * 0.9);
  305. const upperBound = Math.ceil(totalPrice * 1.1);
  306. this.estimatedPriceRange.set(
  307. `¥${lowerBound.toLocaleString()} - ¥${upperBound.toLocaleString()}`
  308. );
  309. }
  310. }
  311. // 匹配案例
  312. matchCases() {
  313. const { style, houseType, area } = this.requirementForm.value;
  314. if (style && houseType && area) {
  315. // 模拟匹配案例
  316. this.matchedCases.set([
  317. {
  318. id: '101',
  319. name: `${style}风格 ${houseType}设计`,
  320. imageUrl: `https://picsum.photos/id/${30 + Math.floor(Math.random() * 10)}/300/200`,
  321. designer: '王设计师',
  322. area: area + '㎡',
  323. similarity: 92
  324. },
  325. {
  326. id: '102',
  327. name: `${houseType} ${style}案例展示`,
  328. imageUrl: `https://picsum.photos/id/${40 + Math.floor(Math.random() * 10)}/300/200`,
  329. designer: '张设计师',
  330. area: (area + 10) + '㎡',
  331. similarity: 85
  332. }
  333. ]);
  334. }
  335. }
  336. // 选择参考案例
  337. selectReferenceCase(caseItem: any) {
  338. const currentCases = this.requirementForm.get('referenceCases')?.value || [];
  339. if (!currentCases.includes(caseItem.id)) {
  340. this.requirementForm.patchValue({
  341. referenceCases: [...currentCases, caseItem.id]
  342. });
  343. }
  344. }
  345. // 移除参考案例
  346. removeReferenceCase(caseId: string) {
  347. const currentCases = this.requirementForm.get('referenceCases')?.value || [];
  348. this.requirementForm.patchValue({
  349. referenceCases: currentCases.filter((id: string) => id !== caseId)
  350. });
  351. }
  352. // 提交表单
  353. submitForm() {
  354. if (this.customerForm.valid) {
  355. this.isSubmitting.set(true);
  356. const formData = {
  357. customerInfo: this.customerForm.value,
  358. requirementInfo: this.requirementForm.value,
  359. estimatedPriceRange: this.estimatedPriceRange(),
  360. createdAt: new Date()
  361. };
  362. // 模拟提交请求
  363. setTimeout(() => {
  364. console.log('提交的表单数据:', formData);
  365. this.isSubmitting.set(false);
  366. this.showSuccessMessage.set(true);
  367. // 1秒后隐藏成功提示并跳转
  368. setTimeout(() => {
  369. this.showSuccessMessage.set(false);
  370. // 发出订单创建成功事件,用于关闭弹窗
  371. const orderData = {
  372. orderId: 'mock-9',
  373. customerName: formData.customerInfo.name,
  374. projectId: 'mock-9'
  375. };
  376. this.orderCreated.emit(orderData);
  377. // 跳转到设计师项目详情页面,传递客服角色标识
  378. this.router.navigate(['/designer/project-detail/mock-9'], {
  379. queryParams: { role: 'customer-service' }
  380. });
  381. }, 1000);
  382. }, 1500);
  383. }
  384. }
  385. // 基于六项核心字段的最小创建可用性判断
  386. minimalReady(): boolean {
  387. const nameCtrl = this.customerForm.get('name');
  388. const phoneCtrl = this.customerForm.get('phone');
  389. const styleCtrl = this.requirementForm.get('style');
  390. const groupCtrl = this.requirementForm.get('projectGroup');
  391. const downPaymentCtrl = this.requirementForm.get('downPayment');
  392. const firstDraftDateCtrl = this.requirementForm.get('firstDraftDate');
  393. const nameOk = !!nameCtrl?.value && nameCtrl.valid;
  394. const phoneOk = !!phoneCtrl?.value && phoneCtrl.valid;
  395. const styleOk = !!styleCtrl?.value;
  396. const groupOk = !!groupCtrl?.value;
  397. const downPaymentOk = downPaymentCtrl != null && downPaymentCtrl.valid && downPaymentCtrl.value !== null && downPaymentCtrl.value !== '';
  398. const firstDraftOk = !!firstDraftDateCtrl?.value;
  399. return !!(nameOk && phoneOk && styleOk && groupOk && downPaymentOk && firstDraftOk);
  400. }
  401. // 创建项目(最小必填:姓名、手机、风格、项目组、首付款、首稿时间)
  402. createProjectMinimal() {
  403. const nameCtrl = this.customerForm.get('name');
  404. const phoneCtrl = this.customerForm.get('phone');
  405. const styleCtrl = this.requirementForm.get('style');
  406. const groupCtrl = this.requirementForm.get('projectGroup');
  407. const downPaymentCtrl = this.requirementForm.get('downPayment');
  408. const firstDraftDateCtrl = this.requirementForm.get('firstDraftDate');
  409. if (!nameCtrl?.value || !phoneCtrl?.value || !styleCtrl?.value || !groupCtrl?.value || downPaymentCtrl?.value === null || !firstDraftDateCtrl?.value) {
  410. this.snackBar.open('请完整填写姓名、手机、风格、项目组、首付款、首稿时间', '关闭', { duration: 3000 });
  411. return;
  412. }
  413. this.isSubmitting.set(true);
  414. const payload = {
  415. customerId: 'temp-' + Date.now(),
  416. customerName: nameCtrl.value,
  417. requirement: {
  418. style: styleCtrl.value,
  419. projectGroup: groupCtrl.value,
  420. downPayment: Number(downPaymentCtrl?.value ?? 0),
  421. firstDraftDate: firstDraftDateCtrl?.value
  422. },
  423. referenceCases: [],
  424. tags: { followUpStatus: '待分配' }
  425. };
  426. this.projectService.createProject(payload).subscribe(
  427. (res: any) => {
  428. this.isSubmitting.set(false);
  429. if (res?.success) {
  430. this.showSuccessMessage.set(true);
  431. this.snackBar.open('项目创建成功', '关闭', { duration: 2000 });
  432. // 延迟跳转到项目详情页面
  433. setTimeout(() => {
  434. this.showSuccessMessage.set(false);
  435. // 发出订单创建成功事件,用于关闭弹窗
  436. const orderData = {
  437. orderId: 'mock-9',
  438. customerName: nameCtrl.value,
  439. projectId: 'mock-9'
  440. };
  441. this.orderCreated.emit(orderData);
  442. // 跳转到设计师项目详情页面,传递客服角色标识
  443. this.router.navigate(['/designer/project-detail/mock-9'], {
  444. queryParams: { role: 'customer-service' }
  445. });
  446. }, 1000);
  447. } else {
  448. this.snackBar.open('创建失败,请稍后重试', '关闭', { duration: 3000 });
  449. }
  450. },
  451. () => {
  452. this.isSubmitting.set(false);
  453. this.snackBar.open('创建失败,请稍后重试', '关闭', { duration: 3000 });
  454. }
  455. );
  456. }
  457. /**
  458. * 创建项目群
  459. */
  460. createProjectGroup() {
  461. // 先检查是否选择了客户
  462. if (!this.selectedCustomer()) {
  463. this.snackBar.open('请先选择客户', '确定', { duration: 2000 });
  464. return;
  465. }
  466. // 显示弹窗
  467. this.dialog.open(ProjectGroupDialog, {
  468. width: '500px',
  469. data: {
  470. selectedCustomer: this.selectedCustomer(),
  471. demandType: this.customerForm.get('demandType')?.value,
  472. preferenceTags: this.preferenceTags,
  473. followUpStatus: this.customerForm.get('followUpStatus')?.value
  474. }
  475. }).afterClosed().subscribe(result => {
  476. if (result && result.confirm) {
  477. const tags = {
  478. demandType: result.demandType,
  479. preferenceTags: result.preferenceTags,
  480. followUpStatus: result.followUpStatus
  481. };
  482. this.isSubmitting.set(true);
  483. this.projectService.createProjectGroup({
  484. customerId: result.customerId,
  485. customerName: result.customerName,
  486. tags
  487. }).subscribe(
  488. (response: any) => {
  489. if (response.success) {
  490. this.snackBar.open(`项目群创建成功,群ID: ${response.groupId}`, '确定', { duration: 3000 });
  491. } else {
  492. this.snackBar.open('项目群创建失败,请稍后重试', '确定', { duration: 2000 });
  493. }
  494. this.isSubmitting.set(false);
  495. },
  496. (error: any) => {
  497. this.snackBar.open('创建项目群时出错,请稍后重试', '确定', { duration: 2000 });
  498. this.isSubmitting.set(false);
  499. }
  500. );
  501. }
  502. });
  503. }
  504. /**
  505. * 快速填写客户信息(通过姓名或手机号)
  506. */
  507. quickFillCustomerInfo(keyword: string) {
  508. if (!keyword.trim()) {
  509. return;
  510. }
  511. // 模拟根据姓名或手机号查询客户信息
  512. setTimeout(() => {
  513. // 这里应该调用实际的API来查询客户信息
  514. const mockCustomer = {
  515. id: 'quick_' + Date.now(),
  516. name: keyword.includes('1') ? '李四' : keyword,
  517. phone: keyword.includes('1') ? keyword : '13900139000',
  518. wechat: 'lisi_wx',
  519. customerType: '老客户',
  520. source: '推荐介绍',
  521. avatar: '',
  522. demandType: 'quality',
  523. preferenceTags: ['北欧风格', '实木'],
  524. followUpStatus: 'confirm'
  525. };
  526. this.selectedCustomer.set(mockCustomer);
  527. this.customerForm.patchValue({
  528. name: mockCustomer.name,
  529. phone: mockCustomer.phone,
  530. wechat: mockCustomer.wechat,
  531. customerType: mockCustomer.customerType,
  532. source: mockCustomer.source,
  533. demandType: mockCustomer.demandType,
  534. followUpStatus: mockCustomer.followUpStatus
  535. });
  536. this.preferenceTags = [...mockCustomer.preferenceTags];
  537. this.snackBar.open('客户信息填写完成', '确定', { duration: 2000 });
  538. }, 1000);
  539. }
  540. // 加载客户历史信息
  541. loadCustomerHistory(customerId: string) {
  542. // 模拟加载客户历史信息
  543. const mockHistory = {
  544. projects: [
  545. { id: '1', name: '三室两厅装修', style: '现代简约', status: '已完成' },
  546. { id: '2', name: '厨房改造', style: '北欧风', status: '进行中' }
  547. ],
  548. feedback: [
  549. '对设计师服务很满意',
  550. '希望能加快施工进度',
  551. '材料质量很好'
  552. ],
  553. preferences: {
  554. style: 'modern',
  555. projectGroup: 'design1'
  556. }
  557. };
  558. // 根据历史偏好预填充项目配置
  559. if (mockHistory.preferences) {
  560. this.projectForm.patchValue({
  561. style: mockHistory.preferences.style,
  562. projectGroup: mockHistory.preferences.projectGroup
  563. });
  564. }
  565. this.snackBar.open('已自动填充客户历史偏好信息', '关闭', {
  566. duration: 3000,
  567. horizontalPosition: 'center',
  568. verticalPosition: 'top'
  569. });
  570. }
  571. // 创建新客户
  572. createNewCustomer() {
  573. // 重置表单为新客户状态
  574. this.selectedCustomer.set(null);
  575. this.customerForm.reset({
  576. customerType: '新客户'
  577. });
  578. this.projectForm.reset();
  579. this.searchKeyword.set('');
  580. this.searchResults.set([]);
  581. }
  582. // 验证项目配置表单
  583. isProjectFormValid(): boolean {
  584. return this.projectForm.valid && this.customerForm.valid;
  585. }
  586. // 获取首付款设置选项
  587. getDownPaymentOptions() {
  588. return [
  589. { value: '30', label: '30%' },
  590. { value: '50', label: '50%' },
  591. { value: '70', label: '70%' },
  592. { value: 'custom', label: '自定义' }
  593. ];
  594. }
  595. // 提交简化的订单
  596. submitSimplifiedOrder() {
  597. if (!this.isProjectFormValid()) {
  598. this.snackBar.open('请完善必填信息', '关闭', {
  599. duration: 3000,
  600. horizontalPosition: 'center',
  601. verticalPosition: 'top'
  602. });
  603. return;
  604. }
  605. this.isSubmitting.set(true);
  606. const orderData = {
  607. customer: this.customerForm.value,
  608. project: this.projectForm.value,
  609. orderTime: this.orderTime(),
  610. orderId: 'mock-' + Date.now(), // 模拟订单ID
  611. status: 'created'
  612. };
  613. // 模拟提交
  614. setTimeout(() => {
  615. this.isSubmitting.set(false);
  616. this.showSuccessMessage.set(true);
  617. this.snackBar.open('订单创建成功!', '关闭', {
  618. duration: 3000,
  619. horizontalPosition: 'center',
  620. verticalPosition: 'top'
  621. });
  622. // 发射订单创建成功事件
  623. this.orderCreated.emit(orderData);
  624. // 3秒后隐藏成功消息
  625. setTimeout(() => {
  626. this.showSuccessMessage.set(false);
  627. }, 3000);
  628. }, 2000);
  629. }
  630. // 返回项目列表页面
  631. goBackToProjectList() {
  632. this.router.navigate(['/customer-service/project-list']);
  633. }
  634. }