urgent-task.service.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. import { Injectable } from '@angular/core';
  2. import { FmodeParse } from 'fmode-ng/parse';
  3. /**
  4. * 紧急事项服务
  5. * 负责UrgentTask的CRUD操作,对接Parse Server数据库
  6. */
  7. @Injectable({
  8. providedIn: 'root'
  9. })
  10. export class UrgentTaskService {
  11. private Parse = FmodeParse.with("nova");
  12. private companyId = localStorage.getItem("company")!;
  13. private currentUserId = localStorage.getItem("profile")!;
  14. constructor() {}
  15. /**
  16. * 查询紧急事项列表(带筛选和分页)
  17. */
  18. async findUrgentTasks(filters?: {
  19. status?: string;
  20. priority?: string;
  21. assignee?: string;
  22. projectId?: string;
  23. isCompleted?: boolean;
  24. }, page: number = 1, pageSize: number = 20): Promise<{ tasks: any[], total: number }> {
  25. try {
  26. const query = this.buildUrgentTaskQuery(filters);
  27. // 分页
  28. query.limit(pageSize);
  29. query.skip((page - 1) * pageSize);
  30. // Include关联数据
  31. query.include("project");
  32. query.include("assignee");
  33. query.include("creator");
  34. query.include("space");
  35. // 排序:优先级高的在前,截止时间早的在前
  36. query.descending("priority");
  37. query.ascending("deadline");
  38. const [tasks, total] = await Promise.all([
  39. query.find(),
  40. query.count()
  41. ]);
  42. // 如果没有数据,直接返回空数组
  43. if (!tasks || tasks.length === 0) {
  44. console.log('紧急事项暂无数据');
  45. return { tasks: [], total: 0 };
  46. }
  47. // 格式化数据
  48. const formattedTasks = tasks.map(t => this.formatTask(t));
  49. return { tasks: formattedTasks, total };
  50. } catch (error) {
  51. console.error('查询紧急事项列表失败:', error);
  52. return { tasks: [], total: 0 };
  53. }
  54. }
  55. /**
  56. * 构建查询条件
  57. */
  58. private buildUrgentTaskQuery(filters?: any) {
  59. try {
  60. const UrgentTask = this.Parse.Object.extend("UrgentTask");
  61. const query = new this.Parse.Query(UrgentTask);
  62. query.equalTo("company", this.getCompanyPointer());
  63. query.notEqualTo("isDeleted", true);
  64. if (filters) {
  65. // 完成状态
  66. if (filters.isCompleted !== undefined) {
  67. query.equalTo("isCompleted", filters.isCompleted);
  68. }
  69. // 任务状态
  70. if (filters.status) {
  71. query.equalTo("status", filters.status);
  72. }
  73. // 优先级
  74. if (filters.priority) {
  75. query.equalTo("priority", filters.priority);
  76. }
  77. // 指派人
  78. if (filters.assignee) {
  79. query.equalTo("assignee", this.getProfilePointer(filters.assignee));
  80. }
  81. // 项目ID
  82. if (filters.projectId) {
  83. query.equalTo("project", this.getProjectPointer(filters.projectId));
  84. }
  85. }
  86. return query;
  87. } catch (error) {
  88. console.error('构建查询条件失败:', error);
  89. const UrgentTask = this.Parse.Object.extend("UrgentTask");
  90. const query = new this.Parse.Query(UrgentTask);
  91. query.equalTo("company", this.getCompanyPointer());
  92. return query;
  93. }
  94. }
  95. /**
  96. * 格式化单个任务数据
  97. */
  98. private formatTask(taskObj: any) {
  99. const project = taskObj.get("project");
  100. const assignee = taskObj.get("assignee");
  101. const creator = taskObj.get("creator");
  102. const space = taskObj.get("space");
  103. const deadline = taskObj.get("deadline");
  104. const now = new Date();
  105. return {
  106. id: taskObj.id,
  107. title: taskObj.get("title") || "",
  108. description: taskObj.get("description") || "",
  109. projectId: project?.id || "",
  110. projectName: project?.get("title") || "",
  111. spaceId: space?.id || "",
  112. spaceName: space?.get("title") || "",
  113. stage: taskObj.get("stage") || "",
  114. region: taskObj.get("region") || "",
  115. priority: taskObj.get("priority") || "medium",
  116. status: taskObj.get("status") || "pending",
  117. assigneeId: assignee?.id || "",
  118. assigneeName: assignee?.get("name") || "未分配",
  119. creatorId: creator?.id || "",
  120. creatorName: creator?.get("name") || "",
  121. deadline: deadline,
  122. isOverdue: deadline ? deadline < now : false,
  123. isCompleted: taskObj.get("isCompleted") || false,
  124. createdAt: taskObj.get("createdAt"),
  125. updatedAt: taskObj.get("updatedAt"),
  126. data: taskObj.get("data") || {}
  127. };
  128. }
  129. /**
  130. * 创建紧急事项
  131. */
  132. async createUrgentTask(taskData: {
  133. title: string;
  134. description?: string;
  135. projectId: string;
  136. spaceId?: string;
  137. stage: string;
  138. region?: string;
  139. priority: string;
  140. assigneeId?: string;
  141. deadline: Date;
  142. }): Promise<any> {
  143. try {
  144. const UrgentTask = this.Parse.Object.extend("UrgentTask");
  145. const task = new UrgentTask();
  146. task.set("company", this.getCompanyPointer());
  147. task.set("creator", this.getCurrentProfilePointer());
  148. task.set("title", taskData.title);
  149. task.set("description", taskData.description || "");
  150. task.set("project", this.getProjectPointer(taskData.projectId));
  151. if (taskData.spaceId) {
  152. task.set("space", this.getSpacePointer(taskData.spaceId));
  153. }
  154. task.set("stage", taskData.stage);
  155. task.set("region", taskData.region || "");
  156. task.set("priority", taskData.priority);
  157. task.set("deadline", taskData.deadline);
  158. task.set("status", "pending");
  159. task.set("isCompleted", false);
  160. task.set("isDeleted", false);
  161. if (taskData.assigneeId) {
  162. task.set("assignee", this.getProfilePointer(taskData.assigneeId));
  163. }
  164. const savedTask = await task.save();
  165. console.log('✅ 紧急事项创建成功:', savedTask.id);
  166. return this.formatTask(savedTask);
  167. } catch (error) {
  168. console.error('❌ 创建紧急事项失败:', error);
  169. throw error;
  170. }
  171. }
  172. /**
  173. * 更新紧急事项
  174. */
  175. async updateUrgentTask(taskId: string, updates: {
  176. title?: string;
  177. description?: string;
  178. stage?: string;
  179. region?: string;
  180. priority?: string;
  181. assigneeId?: string;
  182. deadline?: Date;
  183. status?: string;
  184. isCompleted?: boolean;
  185. }): Promise<any> {
  186. try {
  187. const UrgentTask = this.Parse.Object.extend("UrgentTask");
  188. const query = new this.Parse.Query(UrgentTask);
  189. const task = await query.get(taskId);
  190. if (updates.title !== undefined) task.set("title", updates.title);
  191. if (updates.description !== undefined) task.set("description", updates.description);
  192. if (updates.stage !== undefined) task.set("stage", updates.stage);
  193. if (updates.region !== undefined) task.set("region", updates.region);
  194. if (updates.priority !== undefined) task.set("priority", updates.priority);
  195. if (updates.deadline !== undefined) task.set("deadline", updates.deadline);
  196. if (updates.status !== undefined) task.set("status", updates.status);
  197. if (updates.isCompleted !== undefined) task.set("isCompleted", updates.isCompleted);
  198. if (updates.assigneeId !== undefined) {
  199. task.set("assignee", this.getProfilePointer(updates.assigneeId));
  200. }
  201. const savedTask = await task.save();
  202. console.log('✅ 紧急事项更新成功:', savedTask.id);
  203. return this.formatTask(savedTask);
  204. } catch (error) {
  205. console.error('❌ 更新紧急事项失败:', error);
  206. throw error;
  207. }
  208. }
  209. /**
  210. * 删除紧急事项(软删除)
  211. */
  212. async deleteUrgentTask(taskId: string): Promise<void> {
  213. try {
  214. const UrgentTask = this.Parse.Object.extend("UrgentTask");
  215. const query = new this.Parse.Query(UrgentTask);
  216. const task = await query.get(taskId);
  217. task.set("isDeleted", true);
  218. await task.save();
  219. console.log('✅ 紧急事项删除成功:', taskId);
  220. } catch (error) {
  221. console.error('❌ 删除紧急事项失败:', error);
  222. throw error;
  223. }
  224. }
  225. /**
  226. * 标记任务为已完成
  227. */
  228. async markAsCompleted(taskId: string): Promise<any> {
  229. return this.updateUrgentTask(taskId, {
  230. isCompleted: true,
  231. status: 'completed'
  232. });
  233. }
  234. /**
  235. * 获取项目列表(用于下拉选择)
  236. */
  237. async getProjects(): Promise<any[]> {
  238. try {
  239. const Project = this.Parse.Object.extend("Project");
  240. const query = new this.Parse.Query(Project);
  241. query.equalTo("company", this.getCompanyPointer());
  242. query.notEqualTo("isDeleted", true);
  243. query.limit(1000);
  244. // 不使用select,获取所有字段
  245. const projects = await query.find();
  246. return projects.map(p => ({
  247. id: p.id,
  248. title: p.get("title") || "未命名项目",
  249. stage: p.get("currentStage") || "",
  250. status: p.get("status") || ""
  251. }));
  252. } catch (error) {
  253. console.error('获取项目列表失败:', error);
  254. return [];
  255. }
  256. }
  257. /**
  258. * 获取项目的空间列表(Product表)
  259. */
  260. async getProjectSpaces(projectId: string): Promise<any[]> {
  261. try {
  262. const Product = this.Parse.Object.extend("Product");
  263. const query = new this.Parse.Query(Product);
  264. query.equalTo("project", this.getProjectPointer(projectId));
  265. query.equalTo("company", this.getCompanyPointer());
  266. query.notEqualTo("isDeleted", true);
  267. query.limit(100);
  268. // 不使用select,获取所有字段
  269. const products = await query.find();
  270. return products.map(p => ({
  271. id: p.id,
  272. title: p.get("title") || "未命名空间"
  273. }));
  274. } catch (error) {
  275. console.error('获取空间列表失败:', error);
  276. return [];
  277. }
  278. }
  279. /**
  280. * 获取团队成员列表(用于指派)
  281. */
  282. async getTeamMembers(): Promise<any[]> {
  283. try {
  284. const Profile = this.Parse.Object.extend("Profile");
  285. const query = new this.Parse.Query(Profile);
  286. query.equalTo("company", this.getCompanyPointer());
  287. query.notEqualTo("isDeleted", true);
  288. query.limit(1000);
  289. // 不使用select,获取所有字段
  290. const profiles = await query.find();
  291. return profiles.map(p => ({
  292. id: p.id,
  293. name: p.get("name") || "未命名",
  294. mobile: p.get("mobile") || "",
  295. roleName: p.get("roleName") || ""
  296. }));
  297. } catch (error) {
  298. console.error('获取团队成员列表失败:', error);
  299. return [];
  300. }
  301. }
  302. // ==================== 辅助方法 ====================
  303. private getCompanyPointer() {
  304. return {
  305. __type: "Pointer",
  306. className: "Company",
  307. objectId: this.companyId
  308. };
  309. }
  310. private getCurrentProfilePointer() {
  311. return {
  312. __type: "Pointer",
  313. className: "Profile",
  314. objectId: this.currentUserId
  315. };
  316. }
  317. private getProfilePointer(profileId: string) {
  318. return {
  319. __type: "Pointer",
  320. className: "Profile",
  321. objectId: profileId
  322. };
  323. }
  324. private getProjectPointer(projectId: string) {
  325. return {
  326. __type: "Pointer",
  327. className: "Project",
  328. objectId: projectId
  329. };
  330. }
  331. private getSpacePointer(spaceId: string) {
  332. return {
  333. __type: "Pointer",
  334. className: "Product",
  335. objectId: spaceId
  336. };
  337. }
  338. }