project.service.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. import { Injectable } from '@angular/core';
  2. import { Observable, of } from 'rxjs';
  3. import {
  4. Project,
  5. Task,
  6. RenderProgress,
  7. ModelCheckItem,
  8. CustomerFeedback,
  9. DesignerChange,
  10. Settlement,
  11. SkillTag,
  12. PerformanceData,
  13. MatchingOrder,
  14. ProjectStage
  15. } from '../models/project.model';
  16. // 材料统计数据接口
  17. interface MaterialStatistics {
  18. monthlyAdded: number;
  19. totalCostSaved: number;
  20. personalDownloads: number;
  21. }
  22. // 材料项接口
  23. interface MaterialItem {
  24. id: string;
  25. name: string;
  26. type: string;
  27. style: string;
  28. price: number;
  29. thumbnailUrl: string;
  30. downloadCount: number;
  31. tags: string[];
  32. costSaved: number;
  33. isNew: boolean;
  34. uploadTime: Date;
  35. }
  36. // 材料列表响应接口
  37. interface MaterialsResponse {
  38. materials: MaterialItem[];
  39. total: number;
  40. }
  41. // 异常历史记录接口
  42. interface ExceptionHistory {
  43. id: string;
  44. type: 'failed' | 'stuck' | 'quality' | 'other';
  45. description: string;
  46. submitTime: Date;
  47. status: '待处理' | '处理中' | '已解决';
  48. response?: string;
  49. }
  50. @Injectable({
  51. providedIn: 'root'
  52. })
  53. export class ProjectService {
  54. // 模拟数据 - 实际应用中应从API获取
  55. private projects: Project[] = [
  56. {
  57. id: '1',
  58. name: '现代风格客厅设计',
  59. customerName: '张三',
  60. customerTags: [
  61. { source: '朋友圈', needType: '硬装', preference: '现代', colorAtmosphere: '简约明亮' }
  62. ],
  63. highPriorityNeeds: ['需家具购买建议'],
  64. status: '进行中',
  65. currentStage: '建模',
  66. createdAt: new Date('2025-09-01'),
  67. deadline: new Date('2025-09-15'),
  68. assigneeId: 'designer1',
  69. assigneeName: '设计师A',
  70. skillsRequired: ['现代风格', '硬装']
  71. },
  72. {
  73. id: '2',
  74. name: '宋式风格卧室设计',
  75. customerName: '李四',
  76. customerTags: [
  77. { source: '信息流', needType: '软装', preference: '宋式', colorAtmosphere: '典雅古朴' }
  78. ],
  79. highPriorityNeeds: [],
  80. status: '进行中',
  81. currentStage: '渲染',
  82. createdAt: new Date('2025-09-02'),
  83. deadline: new Date('2025-09-20'),
  84. assigneeId: 'designer1',
  85. assigneeName: '设计师A',
  86. skillsRequired: ['宋式风格', '软装']
  87. },
  88. {
  89. id: '3',
  90. name: '欧式风格厨房设计',
  91. customerName: '王五',
  92. customerTags: [
  93. { source: '朋友圈', needType: '硬装', preference: '欧式', colorAtmosphere: '豪华温馨' }
  94. ],
  95. highPriorityNeeds: ['需快速交付'],
  96. status: '已完成',
  97. currentStage: '完成',
  98. createdAt: new Date('2025-08-20'),
  99. deadline: new Date('2025-09-05'),
  100. assigneeId: 'designer1',
  101. assigneeName: '设计师A',
  102. skillsRequired: ['欧式风格', '硬装']
  103. }
  104. ];
  105. private tasks: Task[] = [
  106. {
  107. id: 't1',
  108. projectId: '1',
  109. projectName: '现代风格客厅设计',
  110. title: '完成客厅建模',
  111. stage: '建模',
  112. deadline: new Date('2025-09-10'),
  113. isOverdue: false,
  114. isCompleted: false,
  115. priority: 'high',
  116. assignee: '设计师A',
  117. description: '根据客户需求完成客厅3D模型构建'
  118. },
  119. {
  120. id: 't2',
  121. projectId: '2',
  122. projectName: '宋式风格卧室设计',
  123. title: '确认渲染结果',
  124. stage: '渲染',
  125. deadline: new Date('2025-09-12'),
  126. isOverdue: false,
  127. isCompleted: false,
  128. priority: 'medium',
  129. assignee: '设计师B',
  130. description: '审核渲染效果并与客户确认'
  131. },
  132. {
  133. id: 't3',
  134. projectId: '1',
  135. projectName: '现代风格客厅设计',
  136. title: '处理客户反馈',
  137. stage: '后期',
  138. deadline: new Date('2025-09-08'),
  139. isOverdue: true,
  140. isCompleted: false,
  141. priority: 'high',
  142. assignee: '客服',
  143. description: '整理客户反馈意见并传达给设计团队'
  144. }
  145. ];
  146. private renderProgresses: RenderProgress[] = [
  147. {
  148. id: 'rp1',
  149. projectId: '2',
  150. completionRate: 60,
  151. estimatedTimeRemaining: 1,
  152. status: '进行中',
  153. updatedAt: new Date()
  154. }
  155. ];
  156. private modelCheckItems: ModelCheckItem[] = [
  157. { id: 'm1', name: '尺寸准确性', isPassed: true },
  158. { id: 'm2', name: '比例协调性', isPassed: true },
  159. { id: 'm3', name: '户型匹配度', isPassed: false, notes: '需调整沙发位置' }
  160. ];
  161. private feedbacks: CustomerFeedback[] = [
  162. {
  163. id: 'f1',
  164. projectId: '1',
  165. content: '客厅设计不太满意',
  166. isSatisfied: false,
  167. problemLocation: '沙发区域',
  168. expectedEffect: '更宽敞舒适',
  169. referenceCase: '提供了参考图片',
  170. status: '待处理',
  171. createdAt: new Date('2025-09-07')
  172. }
  173. ];
  174. private settlements: Settlement[] = [
  175. {
  176. id: 's1',
  177. projectId: '3',
  178. stage: '建模',
  179. amount: 3000,
  180. percentage: 30,
  181. status: '已结算',
  182. createdAt: new Date('2025-08-25'),
  183. settledAt: new Date('2025-09-01')
  184. },
  185. {
  186. id: 's2',
  187. projectId: '3',
  188. stage: '渲染',
  189. amount: 5000,
  190. percentage: 50,
  191. status: '已结算',
  192. createdAt: new Date('2025-08-28'),
  193. settledAt: new Date('2025-09-01')
  194. },
  195. {
  196. id: 's3',
  197. projectId: '3',
  198. stage: '后期',
  199. amount: 2000,
  200. percentage: 20,
  201. status: '已结算',
  202. createdAt: new Date('2025-09-02'),
  203. settledAt: new Date('2025-09-05')
  204. },
  205. {
  206. id: 's4',
  207. projectId: '1',
  208. stage: '建模',
  209. amount: 3000,
  210. percentage: 30,
  211. status: '待结算',
  212. createdAt: new Date('2025-09-06')
  213. }
  214. ];
  215. private skillTags: SkillTag[] = [
  216. { id: 'sk1', name: '现代风格', level: 5, count: 10 },
  217. { id: 'sk2', name: '宋式风格', level: 3, count: 5 },
  218. { id: 'sk3', name: '硬装', level: 5, count: 8 },
  219. { id: 'sk4', name: '软装', level: 3, count: 4 }
  220. ];
  221. private performanceData: PerformanceData[] = [
  222. { month: '2025-08', projectCompletionRate: 90, customerSatisfaction: 95, deliveryOnTimeRate: 85 },
  223. { month: '2025-09', projectCompletionRate: 85, customerSatisfaction: 90, deliveryOnTimeRate: 90 },
  224. { month: '2025-10', projectCompletionRate: 95, customerSatisfaction: 92, deliveryOnTimeRate: 88 }
  225. ];
  226. private matchingOrders: MatchingOrder[] = [
  227. {
  228. id: 'mo1',
  229. projectName: '新中式风格书房设计',
  230. requiredSkills: ['宋式风格', '硬装'],
  231. matchRate: 90,
  232. customerLevel: '优质'
  233. },
  234. {
  235. id: 'mo2',
  236. projectName: '北欧风格餐厅设计',
  237. requiredSkills: ['现代风格', '软装'],
  238. matchRate: 80,
  239. customerLevel: '普通'
  240. }
  241. ];
  242. // 获取当前设计师的项目列表
  243. getProjects(): Observable<Project[]> {
  244. return of(this.projects);
  245. }
  246. // 获取项目详情
  247. getProjectById(id: string): Observable<Project | undefined> {
  248. return of(this.projects.find(project => project.id === id));
  249. }
  250. // 获取待办任务
  251. getTasks(): Observable<Task[]> {
  252. return of(this.tasks);
  253. }
  254. // 标记任务完成
  255. markTaskAsCompleted(taskId: string): Observable<Task> {
  256. const task = this.tasks.find(t => t.id === taskId);
  257. if (task) {
  258. task.isCompleted = true;
  259. task.completedDate = new Date();
  260. }
  261. return of(task as Task);
  262. }
  263. // 获取渲染进度
  264. getRenderProgress(projectId: string): Observable<RenderProgress | undefined> {
  265. return of(this.renderProgresses.find(rp => rp.projectId === projectId));
  266. }
  267. // 获取模型检查清单
  268. getModelCheckItems(): Observable<ModelCheckItem[]> {
  269. return of(this.modelCheckItems);
  270. }
  271. // 更新模型检查项
  272. updateModelCheckItem(itemId: string, isPassed: boolean): Observable<ModelCheckItem> {
  273. const item = this.modelCheckItems.find(i => i.id === itemId);
  274. if (item) {
  275. item.isPassed = isPassed;
  276. }
  277. return of(item as ModelCheckItem);
  278. }
  279. // 获取客户反馈
  280. getCustomerFeedbacks(): Observable<CustomerFeedback[]> {
  281. return of(this.feedbacks);
  282. }
  283. // 更新反馈状态
  284. updateFeedbackStatus(feedbackId: string, status: '处理中' | '已解决'): Observable<CustomerFeedback> {
  285. const feedback = this.feedbacks.find(f => f.id === feedbackId);
  286. if (feedback) {
  287. feedback.status = status;
  288. feedback.updatedAt = new Date();
  289. }
  290. return of(feedback as CustomerFeedback);
  291. }
  292. // 获取结算记录
  293. getSettlements(): Observable<Settlement[]> {
  294. return of(this.settlements);
  295. }
  296. // 获取技能标签
  297. getSkillTags(): Observable<SkillTag[]> {
  298. return of(this.skillTags);
  299. }
  300. // 获取绩效数据
  301. getPerformanceData(): Observable<PerformanceData[]> {
  302. return of(this.performanceData);
  303. }
  304. // 获取匹配订单
  305. getMatchingOrders(): Observable<MatchingOrder[]> {
  306. return of(this.matchingOrders);
  307. }
  308. // 生成需求确认清单
  309. generateRequirementChecklist(projectId: string): Observable<string[]> {
  310. return of([
  311. '个性化需求已确认',
  312. '色彩氛围已确认',
  313. '硬装/软装范围已确认',
  314. '资料提交截止时间已确认'
  315. ]);
  316. }
  317. // 生成提醒话术
  318. generateReminderMessage(type: 'overdue' | 'stagnation'): Observable<string> {
  319. if (type === 'overdue') {
  320. return of('当前处于对图期,需1小时内回复,若您需时间梳理需求,可约定XX时间沟通');
  321. } else {
  322. return of('接下来将推进新项目,若需修改请提前1天预约');
  323. }
  324. }
  325. // 更新项目阶段
  326. updateProjectStage(projectId: string, stage: ProjectStage): Observable<Project | undefined> {
  327. const project = this.projects.find(p => p.id === projectId);
  328. if (project) {
  329. project.currentStage = stage;
  330. }
  331. return of(project);
  332. }
  333. // 获取材料统计数据
  334. getMaterialStatistics(): Observable<MaterialStatistics> {
  335. return of({
  336. monthlyAdded: 15,
  337. totalCostSaved: 2800,
  338. personalDownloads: 42
  339. });
  340. }
  341. // 获取异常历史记录
  342. getExceptionHistories(projectId: string): Observable<ExceptionHistory[]> {
  343. return of([
  344. {
  345. id: 'eh1',
  346. type: 'quality',
  347. description: '光线效果不符合预期',
  348. submitTime: new Date('2025-09-05'),
  349. status: '已解决',
  350. response: '已调整灯光参数'
  351. },
  352. {
  353. id: 'eh2',
  354. type: 'stuck',
  355. description: '沙发尺寸需要调整',
  356. submitTime: new Date('2025-09-07'),
  357. status: '待处理'
  358. }
  359. ]);
  360. }
  361. // 更新收藏材料状态
  362. updateFavoriteMaterial(materialId: string, isFavorite: boolean): Observable<void> {
  363. // 模拟API调用
  364. console.log(`${isFavorite ? '添加' : '取消'}材料收藏:`, materialId);
  365. return of(void 0);
  366. }
  367. // 获取收藏材料列表
  368. getFavoriteMaterials(): Observable<string[]> {
  369. // 模拟返回收藏的材料ID列表
  370. return of(['mat1', 'mat3', 'mat5']);
  371. }
  372. // 获取材料列表
  373. getMaterials(
  374. searchQuery: string = '',
  375. filterType: string = '',
  376. filterStyle: string = '',
  377. filterPrice: string = '',
  378. page: number = 1,
  379. pageSize: number = 10
  380. ): Observable<MaterialsResponse> {
  381. // 模拟材料数据
  382. const mockMaterials: MaterialItem[] = [
  383. { id: 'mat1', name: '现代风格沙发', type: '家具', style: '现代', price: 2800, thumbnailUrl: 'https://picsum.photos/200/150', downloadCount: 120, tags: ['现代', '舒适', '客厅', '布艺'], costSaved: 500, isNew: false, uploadTime: new Date('2025-08-15') },
  384. { id: 'mat2', name: '宋式风格茶几', type: '家具', style: '宋式', price: 1500, thumbnailUrl: 'https://picsum.photos/200/151', downloadCount: 85, tags: ['宋式', '古典', '实木', '客厅'], costSaved: 300, isNew: true, uploadTime: new Date('2025-09-07') },
  385. { id: 'mat3', name: '欧式吊灯', type: '灯具', style: '欧式', price: 2200, thumbnailUrl: 'https://picsum.photos/200/152', downloadCount: 150, tags: ['欧式', '奢华', '客厅', '水晶'], costSaved: 450, isNew: false, uploadTime: new Date('2025-08-20') },
  386. { id: 'mat4', name: '中式地毯', type: '纺织品', style: '中式', price: 1800, thumbnailUrl: 'https://picsum.photos/200/153', downloadCount: 95, tags: ['中式', '传统', '卧室', '羊毛'], costSaved: 350, isNew: false, uploadTime: new Date('2025-08-25') },
  387. { id: 'mat5', name: '北欧风格窗帘', type: '纺织品', style: '北欧', price: 1200, thumbnailUrl: 'https://picsum.photos/200/154', downloadCount: 130, tags: ['北欧', '简约', '卧室', '亚麻'], costSaved: 250, isNew: true, uploadTime: new Date('2025-09-05') }
  388. ];
  389. // 简单的搜索和过滤逻辑
  390. let filtered = [...mockMaterials];
  391. if (searchQuery) {
  392. filtered = filtered.filter(m => m.name.toLowerCase().includes(searchQuery.toLowerCase()));
  393. }
  394. if (filterType) {
  395. filtered = filtered.filter(m => m.type === filterType);
  396. }
  397. if (filterStyle) {
  398. filtered = filtered.filter(m => m.style === filterStyle);
  399. }
  400. // 分页
  401. const startIndex = (page - 1) * pageSize;
  402. const paginated = filtered.slice(startIndex, startIndex + pageSize);
  403. return of({ materials: paginated, total: filtered.length });
  404. }
  405. // 记录材料下载
  406. recordMaterialDownload(materialId: string): Observable<void> {
  407. // 模拟下载记录
  408. console.log('记录材料下载:', materialId);
  409. return of(void 0);
  410. }
  411. // 创建项目
  412. createProject(projectData: {
  413. customerId: string;
  414. customerName: string;
  415. requirement: any;
  416. referenceCases: any[];
  417. tags: {
  418. demandType?: string;
  419. preferenceTags?: string[];
  420. followUpStatus?: string;
  421. };
  422. }): Observable<{ success: boolean; projectId: string }> {
  423. // 模拟API调用
  424. console.log('创建项目:', projectData);
  425. // 模拟返回创建的项目ID
  426. return of({ success: true, projectId: 'new-project-' + Date.now() });
  427. }
  428. // 创建项目群
  429. createProjectGroup(groupData: {
  430. customerId: string;
  431. customerName: string;
  432. tags?: {
  433. demandType?: string;
  434. preferenceTags?: string[];
  435. followUpStatus?: string;
  436. };
  437. }): Observable<{ success: boolean; groupId: string }> {
  438. // 模拟API调用
  439. console.log('创建项目群:', groupData);
  440. // 模拟返回创建的群组ID
  441. return of({ success: true, groupId: 'new-group-' + Date.now() });
  442. }
  443. }