project.service.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. import { Injectable } from '@angular/core';
  2. import { AdminDataService } from './admin-data.service';
  3. import { FmodeObject } from 'fmode-ng/core';
  4. /**
  5. * 项目管理数据服务
  6. */
  7. @Injectable({
  8. providedIn: 'root'
  9. })
  10. export class ProjectService {
  11. constructor(private adminData: AdminDataService) {}
  12. /**
  13. * 查询项目列表
  14. */
  15. async findProjects(options?: {
  16. status?: string;
  17. keyword?: string;
  18. skip?: number;
  19. limit?: number;
  20. }): Promise<FmodeObject[]> {
  21. return await this.adminData.findAll('Project', {
  22. include: ['customer', 'assignee'],
  23. skip: options?.skip || 0,
  24. limit: options?.limit || 20,
  25. descending: 'updatedAt',
  26. additionalQuery: query => {
  27. if (options?.status) {
  28. query.equalTo('status', options.status);
  29. }
  30. if (options?.keyword) {
  31. const kw = options.keyword.trim();
  32. if (kw) {
  33. // 搜索项目标题
  34. query.matches('title', new RegExp(kw, 'i'));
  35. }
  36. }
  37. }
  38. });
  39. }
  40. /**
  41. * 统计项目数量
  42. */
  43. async countProjects(status?: string): Promise<number> {
  44. return await this.adminData.count('Project', query => {
  45. if (status) {
  46. query.equalTo('status', status);
  47. }
  48. });
  49. }
  50. /**
  51. * 根据ID获取项目
  52. */
  53. async getProject(objectId: string): Promise<FmodeObject | null> {
  54. return await this.adminData.getById('Project', objectId, [
  55. 'customer',
  56. 'assignee'
  57. ]);
  58. }
  59. /**
  60. * 创建项目
  61. */
  62. async createProject(data: {
  63. title: string;
  64. customerId?: string;
  65. assigneeId?: string;
  66. status?: string;
  67. currentStage?: string;
  68. deadline?: Date;
  69. data?: any;
  70. }): Promise<FmodeObject> {
  71. const projectData: any = {
  72. title: data.title,
  73. status: data.status || '待分配',
  74. currentStage: data.currentStage || '订单分配'
  75. };
  76. // 设置客户指针
  77. if (data.customerId) {
  78. projectData.customer = {
  79. __type: 'Pointer',
  80. className: 'ContactInfo',
  81. objectId: data.customerId
  82. };
  83. }
  84. // 设置负责人指针
  85. if (data.assigneeId) {
  86. projectData.assignee = {
  87. __type: 'Pointer',
  88. className: 'Profile',
  89. objectId: data.assigneeId
  90. };
  91. }
  92. if (data.deadline) {
  93. projectData.deadline = data.deadline;
  94. }
  95. if (data.data) {
  96. projectData.data = data.data;
  97. }
  98. const project = this.adminData.createObject('Project', projectData);
  99. return await this.adminData.save(project);
  100. }
  101. /**
  102. * 更新项目
  103. */
  104. async updateProject(
  105. objectId: string,
  106. updates: {
  107. title?: string;
  108. customerId?: string;
  109. assigneeId?: string;
  110. status?: string;
  111. currentStage?: string;
  112. deadline?: Date;
  113. data?: any;
  114. }
  115. ): Promise<FmodeObject | null> {
  116. const project = await this.getProject(objectId);
  117. if (!project) {
  118. return null;
  119. }
  120. if (updates.title !== undefined) {
  121. project.set('title', updates.title);
  122. }
  123. if (updates.customerId !== undefined) {
  124. project.set('customer', {
  125. __type: 'Pointer',
  126. className: 'ContactInfo',
  127. objectId: updates.customerId
  128. });
  129. }
  130. if (updates.assigneeId !== undefined) {
  131. project.set('assignee', {
  132. __type: 'Pointer',
  133. className: 'Profile',
  134. objectId: updates.assigneeId
  135. });
  136. }
  137. if (updates.status !== undefined) {
  138. project.set('status', updates.status);
  139. }
  140. if (updates.currentStage !== undefined) {
  141. project.set('currentStage', updates.currentStage);
  142. }
  143. if (updates.deadline !== undefined) {
  144. project.set('deadline', updates.deadline);
  145. }
  146. if (updates.data !== undefined) {
  147. const currentData = project.get('data') || {};
  148. project.set('data', { ...currentData, ...updates.data });
  149. }
  150. return await this.adminData.save(project);
  151. }
  152. /**
  153. * 删除项目(软删除)
  154. */
  155. async deleteProject(objectId: string): Promise<boolean> {
  156. const project = await this.getProject(objectId);
  157. if (!project) {
  158. return false;
  159. }
  160. await this.adminData.softDelete(project);
  161. return true;
  162. }
  163. /**
  164. * 批量删除项目
  165. */
  166. async deleteProjects(objectIds: string[]): Promise<number> {
  167. const projects = await Promise.all(
  168. objectIds.map(id => this.getProject(id))
  169. );
  170. const validProjects = projects.filter((p): p is FmodeObject => p !== null);
  171. if (validProjects.length === 0) {
  172. return 0;
  173. }
  174. await this.adminData.softDeleteBatch(validProjects);
  175. return validProjects.length;
  176. }
  177. /**
  178. * 转换为JSON
  179. */
  180. toJSON(project: FmodeObject): any {
  181. const json = this.adminData.toJSON(project);
  182. // 处理关联对象
  183. if (json.customer && typeof json.customer === 'object') {
  184. json.customerName = json.customer.name || '';
  185. json.customerId = json.customer.objectId;
  186. }
  187. if (json.assignee && typeof json.assignee === 'object') {
  188. json.assigneeName = json.assignee.name || '';
  189. json.assigneeId = json.assignee.objectId;
  190. }
  191. return json;
  192. }
  193. /**
  194. * 批量转换
  195. */
  196. toJSONArray(projects: FmodeObject[]): any[] {
  197. return projects.map(p => this.toJSON(p));
  198. }
  199. }