@mu-cabin/opms-permission 0.8.35 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,8 +1,29 @@
1
1
  // src/utils/storage.ts
2
2
  var Storage = class {
3
+ constructor() {
4
+ this.currentVersion = "1.0.0";
5
+ }
3
6
  setSystemId(systemId) {
4
7
  this.systemId = systemId;
5
8
  }
9
+ /**
10
+ * Set the current version for new data
11
+ * If version changes, all existing data for this systemId will be cleared
12
+ */
13
+ setVersion(version) {
14
+ if (this.currentVersion !== version) {
15
+ this.clear();
16
+ this.currentVersion = version;
17
+ } else {
18
+ this.currentVersion = version;
19
+ }
20
+ }
21
+ /**
22
+ * Get the current version
23
+ */
24
+ getVersion() {
25
+ return this.currentVersion;
26
+ }
6
27
  prefixKey(key) {
7
28
  return this.systemId !== void 0 ? `systemId-${this.systemId}-${key}` : key;
8
29
  }
@@ -12,24 +33,35 @@ var Storage = class {
12
33
  setItem(key, value, expireMinutes) {
13
34
  const data = {
14
35
  value,
15
- expire: expireMinutes ? Date.now() + expireMinutes * 60 * 1e3 : null
36
+ expire: expireMinutes ? Date.now() + expireMinutes * 60 * 1e3 : null,
37
+ version: this.currentVersion,
38
+ timestamp: Date.now()
16
39
  };
17
40
  localStorage.setItem(this.prefixKey(key), JSON.stringify(data));
18
41
  }
19
42
  /**
20
43
  * Get an item from localStorage, returns undefined if expired or not found
44
+ * Automatically expires data if version is different
21
45
  */
22
46
  getItem(key) {
23
47
  const raw = localStorage.getItem(this.prefixKey(key));
24
48
  if (!raw) return void 0;
25
49
  try {
26
50
  const data = JSON.parse(raw);
51
+ if (!data.version) {
52
+ data.version = "0.0.0";
53
+ }
27
54
  if (data.expire && Date.now() > data.expire) {
28
55
  localStorage.removeItem(this.prefixKey(key));
29
56
  return void 0;
30
57
  }
58
+ if (data.version !== this.currentVersion) {
59
+ localStorage.removeItem(this.prefixKey(key));
60
+ return void 0;
61
+ }
31
62
  return data.value;
32
- } catch {
63
+ } catch (error) {
64
+ console.error("Error parsing stored data:", error);
33
65
  return void 0;
34
66
  }
35
67
  }
@@ -39,6 +71,44 @@ var Storage = class {
39
71
  removeItem(key) {
40
72
  localStorage.removeItem(this.prefixKey(key));
41
73
  }
74
+ /**
75
+ * Clear all data for the current systemId
76
+ */
77
+ clear() {
78
+ if (this.systemId !== void 0) {
79
+ const prefix = `systemId-${this.systemId}-`;
80
+ Object.keys(localStorage).filter((key) => key.startsWith(prefix)).forEach((key) => localStorage.removeItem(key));
81
+ }
82
+ }
83
+ /**
84
+ * Get all keys for the current systemId
85
+ */
86
+ getKeys() {
87
+ if (this.systemId === void 0) {
88
+ return Object.keys(localStorage);
89
+ }
90
+ const prefix = `systemId-${this.systemId}-`;
91
+ return Object.keys(localStorage).filter((key) => key.startsWith(prefix)).map((key) => key.substring(prefix.length));
92
+ }
93
+ /**
94
+ * Check if a key exists
95
+ */
96
+ hasKey(key) {
97
+ return localStorage.getItem(this.prefixKey(key)) !== null;
98
+ }
99
+ /**
100
+ * Get storage info for debugging
101
+ */
102
+ getStorageInfo() {
103
+ const totalKeys = Object.keys(localStorage).length;
104
+ const systemKeys = this.getKeys().length;
105
+ return {
106
+ systemId: this.systemId,
107
+ currentVersion: this.currentVersion,
108
+ totalKeys,
109
+ systemKeys
110
+ };
111
+ }
42
112
  };
43
113
  var storage = new Storage();
44
114
 
@@ -194,8 +264,6 @@ import axios from "axios";
194
264
  var USER_INFO_KEY = "opms_user_info";
195
265
  var RESOURCE_KEY = "opms_resources";
196
266
  var TOKEN_KEY = "omps_authorization";
197
- var ORG_COMPANY_KEY = "opms_org_company";
198
- var USER_ORG_KEY = "opms_user_org";
199
267
 
200
268
  // src/api.ts
201
269
  var axiosClient = axios.create();
@@ -222,6 +290,17 @@ axiosClient.interceptors.response.use(
222
290
  return Promise.reject(error);
223
291
  }
224
292
  );
293
+ var EnumOrgQueryMode = /* @__PURE__ */ ((EnumOrgQueryMode2) => {
294
+ EnumOrgQueryMode2["BY_ROLES"] = "BY_ROLES";
295
+ EnumOrgQueryMode2["BY_DEPT"] = "BY_DEPT";
296
+ return EnumOrgQueryMode2;
297
+ })(EnumOrgQueryMode || {});
298
+ var EnumOrgQueryScope = /* @__PURE__ */ ((EnumOrgQueryScope2) => {
299
+ EnumOrgQueryScope2["ONLY_BRANCH"] = "ONLY_BRANCH";
300
+ EnumOrgQueryScope2["STEWARD_UNIT"] = "STEWARD_UNIT";
301
+ EnumOrgQueryScope2["WITH_DEPARTMENT"] = "WITH_DEPARTMENT";
302
+ return EnumOrgQueryScope2;
303
+ })(EnumOrgQueryScope || {});
225
304
  async function login(baseUrl, authorizationCode) {
226
305
  return await axiosClient.get(
227
306
  `${baseUrl}/opmsDefaultAuth/oauthLogin`,
@@ -247,9 +326,16 @@ async function queryResource(baseUrl, params) {
247
326
  params
248
327
  );
249
328
  }
250
- async function getUserOrgTree(baseUrl) {
329
+ async function getOrgTree(baseUrl, params) {
251
330
  return await axiosClient.post(
252
- `${baseUrl}/user/orgTree`
331
+ `${baseUrl}/opmsDefaultUser/orgTree`,
332
+ params
333
+ );
334
+ }
335
+ async function getUserOrgTree(baseUrl, params) {
336
+ return await axiosClient.post(
337
+ `${baseUrl}/opmsDefaultUser/userOrgTree`,
338
+ params
253
339
  );
254
340
  }
255
341
  async function queryOrgCompanies(baseUrl, params) {
@@ -259,6 +345,104 @@ async function queryOrgCompanies(baseUrl, params) {
259
345
  );
260
346
  }
261
347
 
348
+ // src/utils/eventEmitter.ts
349
+ var EventEmitter = class {
350
+ constructor(allowedEvents) {
351
+ this.eventListeners = /* @__PURE__ */ new Map();
352
+ this.allowedEvents = new Set(allowedEvents || []);
353
+ }
354
+ /**
355
+ * Add event listener
356
+ */
357
+ listen(event, listener) {
358
+ if (this.allowedEvents.size > 0 && !this.allowedEvents.has(event)) {
359
+ const allowedEventsList = Array.from(this.allowedEvents).join(", ");
360
+ throw new Error(
361
+ `Event "${String(event)}" is not registered. Allowed events: ${allowedEventsList}`
362
+ );
363
+ }
364
+ if (!this.eventListeners.has(event)) {
365
+ this.eventListeners.set(event, /* @__PURE__ */ new Set());
366
+ }
367
+ const listeners = this.eventListeners.get(event);
368
+ listeners.add(listener);
369
+ return () => {
370
+ listeners.delete(listener);
371
+ if (listeners.size === 0) {
372
+ this.eventListeners.delete(event);
373
+ }
374
+ };
375
+ }
376
+ /**
377
+ * Remove event listener
378
+ */
379
+ unlisten(event, listener) {
380
+ const listeners = this.eventListeners.get(event);
381
+ if (listeners) {
382
+ listeners.delete(listener);
383
+ if (listeners.size === 0) {
384
+ this.eventListeners.delete(event);
385
+ }
386
+ }
387
+ }
388
+ /**
389
+ * Remove all listeners for a specific event or all events
390
+ */
391
+ unlistenAll(event) {
392
+ if (event) {
393
+ this.eventListeners.delete(event);
394
+ } else {
395
+ this.eventListeners.clear();
396
+ }
397
+ }
398
+ /**
399
+ * Emit event to all listeners
400
+ */
401
+ emit(event, data) {
402
+ const listeners = this.eventListeners.get(event);
403
+ if (listeners) {
404
+ listeners.forEach((listener) => {
405
+ try {
406
+ listener(data);
407
+ } catch (error) {
408
+ console.error(`Error in event listener for ${String(event)}:`, error);
409
+ }
410
+ });
411
+ }
412
+ }
413
+ /**
414
+ * Get the number of listeners for a specific event
415
+ */
416
+ getListenerCount(event) {
417
+ const listeners = this.eventListeners.get(event);
418
+ return listeners ? listeners.size : 0;
419
+ }
420
+ /**
421
+ * Check if there are any listeners for a specific event
422
+ */
423
+ hasListeners(event) {
424
+ return this.getListenerCount(event) > 0;
425
+ }
426
+ /**
427
+ * Get all registered event types
428
+ */
429
+ getEventTypes() {
430
+ return Array.from(this.eventListeners.keys());
431
+ }
432
+ /**
433
+ * Get all allowed event types
434
+ */
435
+ getAllowedEvents() {
436
+ return Array.from(this.allowedEvents);
437
+ }
438
+ /**
439
+ * Check if an event is allowed
440
+ */
441
+ isEventAllowed(event) {
442
+ return this.allowedEvents.size === 0 || this.allowedEvents.has(event);
443
+ }
444
+ };
445
+
262
446
  // src/permission.ts
263
447
  var DataHandler = {
264
448
  iterateOrgTree(orgTree) {
@@ -324,16 +508,63 @@ var DataHandler = {
324
508
  var Permission = class {
325
509
  constructor(options) {
326
510
  this._userInfo = null;
327
- this._orgTree = null;
328
- this._orgCompany = null;
329
511
  this.resources = [];
330
512
  this.resourceMap = {};
331
513
  this.widgetMap = {};
332
514
  this.menuList = [];
333
515
  this.menuMap = {};
516
+ // Event emitter instance - only allow tokenChange event
517
+ this.eventEmitter = new EventEmitter(["tokenChange"]);
334
518
  this.baseUrl = options.baseUrl;
335
519
  this.systemId = options.systemId;
336
520
  storage.setSystemId(this.systemId);
521
+ storage.setVersion("1.0.0");
522
+ }
523
+ /**
524
+ * Add event listener
525
+ */
526
+ listen(event, listener) {
527
+ try {
528
+ return this.eventEmitter.listen(event, listener);
529
+ } catch (error) {
530
+ if (error instanceof Error && error.message.includes("not registered")) {
531
+ const allowedEvents = this.eventEmitter.getAllowedEvents();
532
+ throw new Error(
533
+ `Permission event "${String(event)}" is not supported. Available events: ${allowedEvents.join(", ")}`
534
+ );
535
+ }
536
+ throw error;
537
+ }
538
+ }
539
+ /**
540
+ * Remove event listener
541
+ */
542
+ unlisten(event, listener) {
543
+ this.eventEmitter.unlisten(event, listener);
544
+ }
545
+ /**
546
+ * Remove all listeners for a specific event or all events
547
+ */
548
+ unlistenAll(event) {
549
+ this.eventEmitter.unlistenAll(event);
550
+ }
551
+ /**
552
+ * Emit event to all listeners
553
+ */
554
+ emit(event, data) {
555
+ this.eventEmitter.emit(event, data);
556
+ }
557
+ /**
558
+ * Get available events that can be listened to
559
+ */
560
+ getAvailableEvents() {
561
+ return this.eventEmitter.getAllowedEvents();
562
+ }
563
+ /**
564
+ * Check if an event is supported
565
+ */
566
+ isEventSupported(event) {
567
+ return this.eventEmitter.isEventAllowed(event);
337
568
  }
338
569
  /**
339
570
  * Login using code from URL, save userInfo
@@ -361,6 +592,7 @@ var Permission = class {
361
592
  const { token } = obj;
362
593
  url.searchParams.delete("code");
363
594
  storage.setItem(TOKEN_KEY, token);
595
+ this.emit("tokenChange", token);
364
596
  return token;
365
597
  }
366
598
  /**
@@ -371,25 +603,13 @@ var Permission = class {
371
603
  clearData && this.clear();
372
604
  }
373
605
  clear() {
374
- this._userInfo = null;
375
- this._orgTree = null;
376
- this._orgCompany = null;
377
- this.resources = [];
378
- this.resourceMap = {};
379
- this.widgetMap = {};
380
- this.menuList = [];
381
- this.menuMap = {};
382
- storage.removeItem(RESOURCE_KEY);
383
- storage.removeItem(TOKEN_KEY);
384
- storage.removeItem(USER_INFO_KEY);
385
- storage.removeItem(ORG_COMPANY_KEY);
386
- storage.removeItem(USER_ORG_KEY);
606
+ storage.clear();
607
+ this.emit("tokenChange", "");
387
608
  }
388
609
  async getUserInfo() {
389
610
  const data = await getUserInfo(this.baseUrl);
390
611
  const { obj, success, msg, code } = data;
391
- this._userInfo = obj;
392
- return this.userInfo;
612
+ return obj;
393
613
  }
394
614
  /**
395
615
  * Get resources and process to menuList, menuMap, widgetMap (matches app store logic)
@@ -410,17 +630,12 @@ var Permission = class {
410
630
  storage.setItem(
411
631
  RESOURCE_KEY,
412
632
  resources,
413
- 60 * 24
414
- // 24 hours
633
+ 60 * 12
634
+ // 12 hours
415
635
  );
416
636
  }
417
637
  const { resourceMap, widgetMap } = createResourceMap(resources);
418
638
  const { menuList, menuMap } = createMenuList(resources);
419
- this.resources = resources;
420
- this.resourceMap = resourceMap;
421
- this.widgetMap = widgetMap;
422
- this.menuList = menuList;
423
- this.menuMap = menuMap;
424
639
  return {
425
640
  resources,
426
641
  resourceMap,
@@ -430,13 +645,28 @@ var Permission = class {
430
645
  };
431
646
  }
432
647
  /**
433
- * Query and process organization tree
648
+ * Generate cache key for user orgs query
434
649
  */
435
- async queryUserOrgs() {
650
+ generateUserOrgsCacheKey(params) {
651
+ const sortedParams = Object.keys(params).sort().reduce((acc, key) => {
652
+ acc[key] = params[key];
653
+ return acc;
654
+ }, {});
655
+ return `user_orgs_${JSON.stringify(sortedParams)}`;
656
+ }
657
+ /**
658
+ * Query and process organization tree with caching
659
+ */
660
+ async queryUserOrgs(params, config = { force: false, cacheTimeout: 2 }) {
436
661
  try {
437
- let orgTreeData = storage.getItem(USER_ORG_KEY) || null;
662
+ const { force, cacheTimeout = 2 } = config;
663
+ let orgTreeData = null;
664
+ if (!force) {
665
+ const cacheKey = this.generateUserOrgsCacheKey(params);
666
+ orgTreeData = storage.getItem(cacheKey) || null;
667
+ }
438
668
  if (!orgTreeData) {
439
- const res = await getUserOrgTree(this.baseUrl);
669
+ const res = await getUserOrgTree(this.baseUrl, params);
440
670
  const { obj } = res;
441
671
  orgTreeData = iterateNestedArray(obj, (item) => {
442
672
  return {
@@ -451,33 +681,33 @@ var Permission = class {
451
681
  orgId: item.orgId
452
682
  };
453
683
  });
454
- storage.setItem(USER_ORG_KEY, orgTreeData);
684
+ const cacheKey = this.generateUserOrgsCacheKey(params);
685
+ storage.setItem(cacheKey, orgTreeData, cacheTimeout);
455
686
  }
456
687
  const data = handlePermissionTree(orgTreeData, "orgId");
457
- const { noAuthMap } = data;
458
- let { tree } = data;
459
- if (tree.length === 1 && tree[0].orgType === "HEAD" && tree[0].disabled) {
460
- tree = tree[0].children || [];
461
- }
462
- this._orgTree = orgTreeData;
463
- return { orgTree: orgTreeData, orgNoAuthMap: noAuthMap, authOrgTree: tree };
688
+ const { tree } = data;
689
+ return {
690
+ orgTree: tree
691
+ // orgNoAuthMap: noAuthMap,
692
+ // authOrgTree: tree,
693
+ };
464
694
  } catch (error) {
465
695
  console.log(error);
466
696
  return null;
467
697
  }
468
698
  }
469
- async queryCompanies() {
470
- let orgCompanyList = storage.getItem(ORG_COMPANY_KEY);
471
- if (!orgCompanyList) {
472
- const { obj } = await queryOrgCompanies(this.baseUrl, {
473
- queryAllBranches: true
474
- });
475
- orgCompanyList = obj;
476
- storage.setItem(ORG_COMPANY_KEY, orgCompanyList);
477
- }
478
- this._orgCompany = orgCompanyList;
479
- return orgCompanyList;
480
- }
699
+ // async queryCompanies(): Promise<OrgRecord[]> {
700
+ // let orgCompanyList: OrgRecord[] | undefined =
701
+ // storage.getItem(ORG_COMPANY_KEY);
702
+ // if (!orgCompanyList) {
703
+ // const { obj } = await queryOrgCompanies(this.baseUrl, {
704
+ // queryAllBranches: true,
705
+ // });
706
+ // orgCompanyList = obj;
707
+ // storage.setItem(ORG_COMPANY_KEY, orgCompanyList);
708
+ // }
709
+ // return orgCompanyList;
710
+ // }
481
711
  isLogin() {
482
712
  return !!storage.getItem(TOKEN_KEY);
483
713
  }
@@ -486,72 +716,77 @@ var Permission = class {
486
716
  }
487
717
  setToken(token) {
488
718
  storage.setItem(TOKEN_KEY, token);
719
+ this.emit("tokenChange", token);
489
720
  }
490
721
  // --- Getters ---
491
- get userInfo() {
492
- if (!this._userInfo) {
493
- this._userInfo = storage.getItem(USER_INFO_KEY);
494
- }
495
- if (!this._userInfo) return null;
496
- const { account, name, ehrId, crewCode, crewId } = this._userInfo;
497
- return { account, name, ehrId, crewCode, crewId };
498
- }
499
- get hasRootAuth() {
500
- const orgs = this._userInfo?.organizations || [];
501
- const first = orgs[0];
502
- if (!first) return false;
503
- return first.searchPath === "#1";
504
- }
505
- get userOrganizations() {
506
- return this._userInfo?.userOrganizations || [];
507
- }
508
- get allCompanyOptions() {
509
- const orgCompany = this._orgCompany;
510
- if (!orgCompany) return [];
511
- const list = orgCompany.map((v) => ({
512
- label: v.orgName,
513
- value: v.orgCode
514
- }));
515
- list.unshift({ label: "\u5168\u516C\u53F8", value: "EA" });
516
- return list;
517
- }
518
- get companyOptions() {
519
- const orgTree = this._orgTree;
520
- if (!orgTree) return [];
521
- const list = orgTree.map(({ children, ...others }) => ({
522
- ...others,
523
- disabled: false
524
- }));
525
- if (this.hasRootAuth) {
526
- list.unshift({ ...orgTree, label: "\u5168\u516C\u53F8", children: [] });
527
- }
528
- return list;
529
- }
530
- get firstCompanyOrgCode() {
531
- return this.companyOptions?.[0]?.value ?? "";
722
+ // get userInfo(): UserInfo | null {
723
+ // if (!this._userInfo) {
724
+ // this._userInfo = storage.getItem(USER_INFO_KEY);
725
+ // }
726
+ // if (!this._userInfo) return null;
727
+ // const { account, name, ehrId, crewCode, crewId } = this._userInfo;
728
+ // return { account, name, ehrId, crewCode, crewId };
729
+ // }
730
+ // get hasRootAuth() {
731
+ // const orgs = this._userInfo?.organizations || [];
732
+ // const first = orgs[0];
733
+ // if (!first) return false;
734
+ // return first.searchPath === '#1';
735
+ // }
736
+ // get userOrganizations(): UserOrganization[] {
737
+ // return this._userInfo?.userOrganizations || [];
738
+ // }
739
+ /**
740
+ * Get storage information for debugging and monitoring
741
+ */
742
+ getStorageInfo() {
743
+ const keys = storage.getKeys();
744
+ const userOrgsCacheKeys = keys.filter((key) => key.startsWith("user_orgs_"));
745
+ return {
746
+ ...storage.getStorageInfo(),
747
+ permissionKeys: {
748
+ resourceKey: RESOURCE_KEY,
749
+ tokenKey: TOKEN_KEY,
750
+ userInfoKey: USER_INFO_KEY
751
+ },
752
+ hasData: {
753
+ resources: storage.hasKey(RESOURCE_KEY),
754
+ token: storage.hasKey(TOKEN_KEY),
755
+ userInfo: storage.hasKey(USER_INFO_KEY)
756
+ },
757
+ cacheInfo: {
758
+ userOrgsCacheCount: userOrgsCacheKeys.length,
759
+ userOrgsCacheKeys
760
+ }
761
+ };
532
762
  }
533
- get unitOptions() {
534
- const orgTree = this._orgTree;
535
- if (!orgTree) return [];
536
- return orgTree;
763
+ /**
764
+ * Get current storage version
765
+ */
766
+ getStorageVersion() {
767
+ return storage.getVersion();
537
768
  }
538
- get allUnitOptions() {
539
- const orgTree = this._orgTree;
540
- if (!orgTree) return [];
541
- return DataHandler.getAllUnitOptions(orgTree);
769
+ /**
770
+ * Clear all storage data for this system
771
+ */
772
+ clearStorage() {
773
+ storage.clear();
542
774
  }
543
- get firstUnitOrgCode() {
544
- if (this.hasRootAuth) {
545
- return this.companyOptions[1]?.value ?? "";
775
+ /**
776
+ * Clear user orgs cache for specific parameters or all
777
+ */
778
+ clearUserOrgsCache(params) {
779
+ if (params) {
780
+ const cacheKey = this.generateUserOrgsCacheKey(params);
781
+ storage.removeItem(cacheKey);
782
+ } else {
783
+ const keys = storage.getKeys();
784
+ keys.forEach((key) => {
785
+ if (key.startsWith("user_orgs_")) {
786
+ storage.removeItem(key);
787
+ }
788
+ });
546
789
  }
547
- const orgTree = this._orgTree;
548
- if (!orgTree) return "";
549
- return findFirstEnableCode(orgTree) ?? "";
550
- }
551
- get topLevelUnitOrgCodes() {
552
- const orgTree = this._orgTree;
553
- if (!orgTree) return [];
554
- return DataHandler.topLevelUnitOrgCodes(orgTree);
555
790
  }
556
791
  };
557
792
 
@@ -591,7 +826,17 @@ function jumpToSSOLogout({
591
826
  }
592
827
  export {
593
828
  DataHandler,
829
+ EnumOrgQueryMode,
830
+ EnumOrgQueryScope,
831
+ EventEmitter,
594
832
  Permission as OpmsPermission,
833
+ getOrgTree,
834
+ getUserInfo,
835
+ getUserOrgTree,
595
836
  jumpToSSOLogin,
596
- jumpToSSOLogout
837
+ jumpToSSOLogout,
838
+ login,
839
+ logout,
840
+ queryOrgCompanies,
841
+ queryResource
597
842
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mu-cabin/opms-permission",
3
- "version": "0.8.35",
3
+ "version": "0.9.2",
4
4
  "description": "Frontend SDK for OPMS permission and auth management.",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",