profile.service.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import { Injectable } from '@angular/core';
  2. import { FmodeParse, FmodeObject } from 'fmode-ng/parse';
  3. const Parse = FmodeParse.with('nova');
  4. /**
  5. * 全局 Profile 服务
  6. *
  7. * 用途:
  8. * 1. 统一管理当前登录用户的 Profile 信息
  9. * 2. 支持从 localStorage 缓存读取
  10. * 3. 支持企微授权自动同步
  11. * 4. 提供全局单例访问
  12. */
  13. @Injectable({
  14. providedIn: 'root'
  15. })
  16. export class ProfileService {
  17. private currentProfile: FmodeObject | null = null;
  18. private profileCache: Map<string, FmodeObject> = new Map();
  19. constructor() {}
  20. /**
  21. * 获取当前 Profile
  22. *
  23. * 逻辑优先级:
  24. * 1. 内存缓存
  25. * 2. localStorage 的 "Parse/ProfileId"
  26. * 3. 企微授权同步
  27. *
  28. * @param cid 公司ID,用于企微授权(可选)
  29. * @param forceRefresh 强制刷新,默认 false
  30. * @returns Profile 对象或 null
  31. */
  32. async getCurrentProfile(cid?: string, forceRefresh = false): Promise<FmodeObject | null> {
  33. try {
  34. // 1. 检查内存缓存
  35. if (!forceRefresh && this.currentProfile) {
  36. return this.currentProfile;
  37. }
  38. // 2. 尝试从 localStorage 加载
  39. const profileId = localStorage.getItem('Parse/ProfileId');
  40. if (profileId) {
  41. // 检查缓存
  42. if (!forceRefresh && this.profileCache.has(profileId)) {
  43. this.currentProfile = this.profileCache.get(profileId)!;
  44. return this.currentProfile;
  45. }
  46. // 从数据库加载
  47. try {
  48. const query = new Parse.Query('Profile');
  49. this.currentProfile = await query.get(profileId);
  50. this.profileCache.set(profileId, this.currentProfile);
  51. return this.currentProfile;
  52. } catch (err) {
  53. console.warn('Failed to load Profile from localStorage:', err);
  54. // 清除无效的 profileId
  55. localStorage.removeItem('Parse/ProfileId');
  56. }
  57. }
  58. // 3. 如果提供了 cid,尝试通过企微授权获取
  59. if (cid) {
  60. const profile = await this.syncFromWxwork(cid);
  61. if (profile) {
  62. this.currentProfile = profile;
  63. // 缓存到 localStorage
  64. profile?.id&&localStorage.setItem('Parse/ProfileId', profile.id);
  65. profile?.id&&this.profileCache.set(profile.id, profile);
  66. return profile;
  67. }
  68. }
  69. return null;
  70. } catch (error) {
  71. console.error('Failed to get current profile:', error);
  72. return null;
  73. }
  74. }
  75. /**
  76. * 通过企微授权同步 Profile
  77. *
  78. * @param cid 公司ID
  79. * @returns Profile 对象或 null
  80. */
  81. private async syncFromWxwork(cid: string): Promise<FmodeObject | null> {
  82. try {
  83. // 动态导入 WxworkAuth
  84. const { WxworkAuth } = await import('fmode-ng/core');
  85. const wxAuth = new WxworkAuth({ cid, appId: 'crm' });
  86. // 获取用户信息并同步
  87. const { profile } = await wxAuth.authenticateAndLogin();
  88. return profile;
  89. } catch (error) {
  90. console.error('Failed to sync profile from Wxwork:', error);
  91. return null;
  92. }
  93. }
  94. /**
  95. * 根据 profileId 获取 Profile
  96. *
  97. * @param profileId Profile ID
  98. * @param useCache 是否使用缓存,默认 true
  99. * @returns Profile 对象或 null
  100. */
  101. async getProfileById(profileId: string, useCache = true): Promise<FmodeObject | null> {
  102. try {
  103. // 检查缓存
  104. if (useCache && this.profileCache.has(profileId)) {
  105. return this.profileCache.get(profileId)!;
  106. }
  107. // 从数据库加载
  108. const query = new Parse.Query('Profile');
  109. const profile = await query.get(profileId);
  110. // 更新缓存
  111. this.profileCache.set(profileId, profile);
  112. return profile;
  113. } catch (error) {
  114. console.error('Failed to get profile by id:', error);
  115. return null;
  116. }
  117. }
  118. /**
  119. * 设置当前 Profile
  120. *
  121. * @param profile Profile 对象
  122. */
  123. setCurrentProfile(profile: FmodeObject): void {
  124. this.currentProfile = profile;
  125. if(profile?.id){
  126. this.profileCache.set(profile.id, profile);
  127. localStorage.setItem('Parse/ProfileId', profile.id);
  128. }
  129. }
  130. /**
  131. * 清除当前 Profile 缓存
  132. */
  133. clearCurrentProfile(): void {
  134. this.currentProfile = null;
  135. localStorage.removeItem('Parse/ProfileId');
  136. }
  137. /**
  138. * 清除所有缓存
  139. */
  140. clearCache(): void {
  141. this.currentProfile = null;
  142. this.profileCache.clear();
  143. localStorage.removeItem('Parse/ProfileId');
  144. }
  145. /**
  146. * 获取公司所有员工
  147. *
  148. * @param companyId 公司ID
  149. * @param roleName 角色名称(可选)
  150. * @returns Profile 列表
  151. */
  152. async getCompanyProfiles(companyId: string, roleName?: string): Promise<FmodeObject[]> {
  153. try {
  154. const query = new Parse.Query('Profile');
  155. query.equalTo('company', companyId);
  156. query.notEqualTo('isDeleted', true);
  157. if (roleName) {
  158. query.equalTo('roleName', roleName);
  159. }
  160. query.ascending('name');
  161. query.limit(1000);
  162. return await query.find();
  163. } catch (error) {
  164. console.error('Failed to get company profiles:', error);
  165. return [];
  166. }
  167. }
  168. }