com-angel-authorization 1.0.0 → 1.0.1

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.
@@ -23,9 +23,26 @@ __export(vue_exports, {
23
23
  Can: () => Can,
24
24
  PERMISSION_STORE_KEY: () => PERMISSION_STORE_KEY,
25
25
  PermissionStore: () => import_core2.PermissionStore,
26
+ RESOURCE_PRIVATE_OPTIONS: () => import_resources2.RESOURCE_PRIVATE_OPTIONS,
27
+ RESOURCE_STATUS_DISABLED: () => import_resources2.RESOURCE_STATUS_DISABLED,
28
+ RESOURCE_STATUS_ENABLED: () => import_resources2.RESOURCE_STATUS_ENABLED,
29
+ RESOURCE_STATUS_OPTIONS: () => import_resources2.RESOURCE_STATUS_OPTIONS,
30
+ RESOURCE_TYPE_API: () => import_resources2.RESOURCE_TYPE_API,
31
+ ResourceManager: () => ResourceManager,
32
+ appendQueryParam: () => import_resources2.appendQueryParam,
33
+ buildCreateBody: () => import_resources2.buildCreateBody,
34
+ buildUpdateBody: () => import_resources2.buildUpdateBody,
35
+ createAuthorizationResourceApi: () => import_resources2.createAuthorizationResourceApi,
36
+ createDefaultResourceRequest: () => import_resources2.createDefaultResourceRequest,
26
37
  createPermissionPlugin: () => createPermissionPlugin,
27
38
  createPermissionStore: () => import_core2.createPermissionStore,
28
39
  createVPermission: () => createVPermission,
40
+ extractPagination: () => import_resources2.extractPagination,
41
+ extractRecords: () => import_resources2.extractRecords,
42
+ getAppClientId: () => import_snowflake.getAppClientId,
43
+ getDeviceWorkerId: () => import_snowflake.getDeviceWorkerId,
44
+ mapAuthorizationResource: () => import_resources2.mapAuthorizationResource,
45
+ snowyflake: () => import_snowflake.snowyflake,
29
46
  useHasPermission: () => useHasPermission,
30
47
  useHasRole: () => useHasRole,
31
48
  usePermission: () => usePermission
@@ -224,16 +241,593 @@ var Can = (0, import_vue2.defineComponent)({
224
241
  }
225
242
  });
226
243
 
244
+ // src/vue/ResourceManager.ts
245
+ var import_vue3 = require("vue");
246
+ var import_resources = require("../resources");
247
+ var PAGE_SIZE_OPTIONS = ["10", "20", "50", "100"];
248
+ function emptyForm() {
249
+ return {
250
+ name: "",
251
+ identification: "",
252
+ status: import_resources.RESOURCE_STATUS_ENABLED,
253
+ private: false,
254
+ description: ""
255
+ };
256
+ }
257
+ var s = {
258
+ root: {
259
+ display: "flex",
260
+ flexDirection: "column",
261
+ gap: "16px",
262
+ padding: "16px",
263
+ color: "#101828",
264
+ fontFamily: '"PingFang SC", "Microsoft YaHei", -apple-system, BlinkMacSystemFont, sans-serif'
265
+ },
266
+ toolbar: {
267
+ display: "flex",
268
+ alignItems: "center",
269
+ justifyContent: "space-between",
270
+ gap: "12px"
271
+ },
272
+ title: { margin: "0", fontSize: "18px", fontWeight: "600" },
273
+ toolbarRight: { display: "flex", alignItems: "center", gap: "8px" },
274
+ error: {
275
+ padding: "10px 12px",
276
+ borderRadius: "8px",
277
+ background: "#fef3f2",
278
+ color: "#b42318",
279
+ fontSize: "13px"
280
+ },
281
+ tableWrap: {
282
+ overflow: "auto",
283
+ border: "1px solid #eaecf0",
284
+ borderRadius: "10px",
285
+ background: "#fff"
286
+ },
287
+ table: { width: "100%", borderCollapse: "collapse", minWidth: "720px" },
288
+ th: {
289
+ textAlign: "left",
290
+ padding: "12px 14px",
291
+ fontSize: "13px",
292
+ fontWeight: "600",
293
+ color: "#475467",
294
+ background: "#f9fafb",
295
+ borderBottom: "1px solid #eaecf0"
296
+ },
297
+ td: {
298
+ padding: "12px 14px",
299
+ fontSize: "14px",
300
+ borderBottom: "1px solid #f2f4f7",
301
+ verticalAlign: "middle"
302
+ },
303
+ empty: {
304
+ padding: "28px",
305
+ textAlign: "center",
306
+ color: "#98a2b3",
307
+ fontSize: "14px"
308
+ },
309
+ code: {
310
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
311
+ fontSize: "13px",
312
+ background: "#f2f4f7",
313
+ padding: "2px 6px",
314
+ borderRadius: "4px"
315
+ },
316
+ badge: {
317
+ display: "inline-block",
318
+ padding: "2px 8px",
319
+ borderRadius: "999px",
320
+ fontSize: "12px",
321
+ fontWeight: "500"
322
+ },
323
+ linkBtn: {
324
+ border: "none",
325
+ background: "transparent",
326
+ color: "#049BAD",
327
+ cursor: "pointer",
328
+ padding: "0 8px 0 0",
329
+ fontSize: "13px"
330
+ },
331
+ pagination: {
332
+ display: "flex",
333
+ alignItems: "center",
334
+ justifyContent: "space-between",
335
+ gap: "12px"
336
+ },
337
+ pageSize: {
338
+ display: "flex",
339
+ alignItems: "center",
340
+ gap: "8px",
341
+ fontSize: "13px",
342
+ color: "#475467"
343
+ },
344
+ pageBtns: { display: "flex", gap: "8px" },
345
+ primaryBtn: {
346
+ border: "none",
347
+ background: "#049BAD",
348
+ color: "#fff",
349
+ borderRadius: "8px",
350
+ padding: "8px 14px",
351
+ cursor: "pointer",
352
+ fontSize: "14px"
353
+ },
354
+ secondaryBtn: {
355
+ border: "1px solid #d0d5dd",
356
+ background: "#fff",
357
+ color: "#344054",
358
+ borderRadius: "8px",
359
+ padding: "8px 14px",
360
+ cursor: "pointer",
361
+ fontSize: "14px"
362
+ },
363
+ select: {
364
+ border: "1px solid #d0d5dd",
365
+ borderRadius: "6px",
366
+ padding: "4px 8px",
367
+ fontSize: "13px"
368
+ },
369
+ mask: {
370
+ position: "fixed",
371
+ inset: "0",
372
+ background: "rgba(16, 24, 40, 0.45)",
373
+ display: "flex",
374
+ alignItems: "center",
375
+ justifyContent: "center",
376
+ zIndex: "1000",
377
+ padding: "16px"
378
+ },
379
+ dialog: {
380
+ width: "100%",
381
+ maxWidth: "480px",
382
+ background: "#fff",
383
+ borderRadius: "12px",
384
+ boxShadow: "0 20px 40px rgba(16,24,40,0.18)"
385
+ },
386
+ dialogHeader: {
387
+ display: "flex",
388
+ alignItems: "center",
389
+ justifyContent: "space-between",
390
+ padding: "14px 16px",
391
+ borderBottom: "1px solid #eaecf0"
392
+ },
393
+ dialogTitle: { margin: "0", fontSize: "16px", fontWeight: "600" },
394
+ iconBtn: {
395
+ border: "none",
396
+ background: "transparent",
397
+ fontSize: "22px",
398
+ lineHeight: "1",
399
+ cursor: "pointer",
400
+ color: "#667085"
401
+ },
402
+ form: { display: "flex", flexDirection: "column", gap: "12px", padding: "16px" },
403
+ field: { display: "flex", flexDirection: "column", gap: "6px" },
404
+ label: { fontSize: "13px", color: "#344054", fontWeight: "500" },
405
+ input: {
406
+ border: "1px solid #d0d5dd",
407
+ borderRadius: "8px",
408
+ padding: "8px 10px",
409
+ fontSize: "14px",
410
+ outline: "none"
411
+ },
412
+ dialogFooter: {
413
+ display: "flex",
414
+ justifyContent: "flex-end",
415
+ gap: "8px",
416
+ paddingTop: "4px"
417
+ }
418
+ };
419
+ var ResourceManager = (0, import_vue3.defineComponent)({
420
+ name: "ResourceManager",
421
+ props: {
422
+ api: {
423
+ type: Object,
424
+ required: true
425
+ },
426
+ title: {
427
+ type: String,
428
+ default: "\u6743\u9650\u70B9\u7BA1\u7406"
429
+ },
430
+ pageSize: {
431
+ type: String,
432
+ default: "20"
433
+ }
434
+ },
435
+ setup(props, { slots }) {
436
+ const records = (0, import_vue3.ref)([]);
437
+ const loading = (0, import_vue3.ref)(false);
438
+ const error = (0, import_vue3.ref)("");
439
+ const pageSize = (0, import_vue3.ref)(props.pageSize);
440
+ const pageToken = (0, import_vue3.ref)("");
441
+ const hasPreviousPage = (0, import_vue3.ref)(false);
442
+ const hasNextPage = (0, import_vue3.ref)(false);
443
+ const dialogOpen = (0, import_vue3.ref)(false);
444
+ const editing = (0, import_vue3.ref)(null);
445
+ const form = (0, import_vue3.reactive)(emptyForm());
446
+ const saving = (0, import_vue3.ref)(false);
447
+ const statusLabel = Object.fromEntries(
448
+ import_resources.RESOURCE_STATUS_OPTIONS.map((o) => [o.value, o.label])
449
+ );
450
+ async function loadList(direction = "current", token = pageToken.value) {
451
+ loading.value = true;
452
+ error.value = "";
453
+ try {
454
+ const result = await props.api.list({
455
+ pagination: {
456
+ pageToken: token,
457
+ pageSize: pageSize.value,
458
+ pageDirection: direction
459
+ }
460
+ });
461
+ records.value = result.records;
462
+ pageToken.value = result.pageToken;
463
+ hasPreviousPage.value = result.hasPreviousPage;
464
+ hasNextPage.value = result.hasNextPage;
465
+ } catch (err) {
466
+ error.value = err instanceof Error ? err.message : "\u52A0\u8F7D\u5931\u8D25";
467
+ } finally {
468
+ loading.value = false;
469
+ }
470
+ }
471
+ function openCreate() {
472
+ editing.value = null;
473
+ Object.assign(form, emptyForm());
474
+ dialogOpen.value = true;
475
+ }
476
+ function openEdit(row) {
477
+ editing.value = row;
478
+ Object.assign(form, {
479
+ name: row.name,
480
+ identification: row.identification,
481
+ status: row.status,
482
+ private: row.private,
483
+ description: row.description
484
+ });
485
+ dialogOpen.value = true;
486
+ }
487
+ function closeDialog() {
488
+ if (!saving.value) dialogOpen.value = false;
489
+ }
490
+ async function handleSubmit(event) {
491
+ event.preventDefault();
492
+ if (!form.name.trim()) {
493
+ error.value = "\u8BF7\u586B\u5199\u6743\u9650\u540D\u79F0";
494
+ return;
495
+ }
496
+ if (!form.identification.trim()) {
497
+ error.value = "\u8BF7\u586B\u5199\u63A5\u53E3\u6807\u8BC6";
498
+ return;
499
+ }
500
+ saving.value = true;
501
+ error.value = "";
502
+ try {
503
+ if (editing.value) {
504
+ await props.api.update(editing.value.resourceId, { ...form });
505
+ } else {
506
+ await props.api.create({ ...form });
507
+ }
508
+ dialogOpen.value = false;
509
+ await loadList("current", "");
510
+ } catch (err) {
511
+ error.value = err instanceof Error ? err.message : "\u4FDD\u5B58\u5931\u8D25";
512
+ } finally {
513
+ saving.value = false;
514
+ }
515
+ }
516
+ async function handleDelete(row) {
517
+ if (!window.confirm(`\u786E\u8BA4\u5220\u9664\u6743\u9650\u70B9\u300C${row.name}\u300D\uFF1F`)) return;
518
+ error.value = "";
519
+ try {
520
+ await props.api.remove(row.resourceId);
521
+ await loadList("current", "");
522
+ } catch (err) {
523
+ error.value = err instanceof Error ? err.message : "\u5220\u9664\u5931\u8D25";
524
+ }
525
+ }
526
+ (0, import_vue3.onMounted)(() => {
527
+ void loadList("current", "");
528
+ });
529
+ (0, import_vue3.watch)(
530
+ () => [props.api, pageSize.value],
531
+ () => {
532
+ pageToken.value = "";
533
+ void loadList("current", "");
534
+ }
535
+ );
536
+ return () => (0, import_vue3.h)("div", { style: s.root }, [
537
+ (0, import_vue3.h)("div", { style: s.toolbar }, [
538
+ (0, import_vue3.h)("h2", { style: s.title }, props.title),
539
+ (0, import_vue3.h)("div", { style: s.toolbarRight }, [
540
+ slots.toolbarExtra?.(),
541
+ (0, import_vue3.h)(
542
+ "button",
543
+ { type: "button", style: s.primaryBtn, onClick: openCreate },
544
+ "\u65B0\u589E"
545
+ )
546
+ ])
547
+ ]),
548
+ error.value ? (0, import_vue3.h)("div", { style: s.error }, error.value) : null,
549
+ (0, import_vue3.h)("div", { style: s.tableWrap }, [
550
+ (0, import_vue3.h)("table", { style: s.table }, [
551
+ (0, import_vue3.h)("thead", [
552
+ (0, import_vue3.h)("tr", [
553
+ (0, import_vue3.h)("th", { style: s.th }, "\u6743\u9650\u540D\u79F0"),
554
+ (0, import_vue3.h)("th", { style: s.th }, "\u63A5\u53E3\u6807\u8BC6"),
555
+ (0, import_vue3.h)("th", { style: s.th }, "\u63CF\u8FF0"),
556
+ (0, import_vue3.h)("th", { style: { ...s.th, width: "90px" } }, "\u72B6\u6001"),
557
+ (0, import_vue3.h)("th", { style: { ...s.th, width: "140px" } }, "\u64CD\u4F5C")
558
+ ])
559
+ ]),
560
+ (0, import_vue3.h)(
561
+ "tbody",
562
+ loading.value ? [
563
+ (0, import_vue3.h)("tr", [
564
+ (0, import_vue3.h)("td", { colspan: 5, style: s.empty }, "\u52A0\u8F7D\u4E2D\u2026")
565
+ ])
566
+ ] : records.value.length === 0 ? [
567
+ (0, import_vue3.h)("tr", [
568
+ (0, import_vue3.h)("td", { colspan: 5, style: s.empty }, "\u6682\u65E0\u6570\u636E")
569
+ ])
570
+ ] : records.value.map(
571
+ (row) => (0, import_vue3.h)("tr", { key: row.resourceId }, [
572
+ (0, import_vue3.h)("td", { style: s.td }, row.name),
573
+ (0, import_vue3.h)("td", { style: s.td }, [
574
+ (0, import_vue3.h)("code", { style: s.code }, row.identification)
575
+ ]),
576
+ (0, import_vue3.h)("td", { style: s.td }, row.description || "\u2014"),
577
+ (0, import_vue3.h)("td", { style: s.td }, [
578
+ (0, import_vue3.h)(
579
+ "span",
580
+ {
581
+ style: {
582
+ ...s.badge,
583
+ background: row.status === import_resources.RESOURCE_STATUS_ENABLED ? "#e8f7ef" : "#f4f4f5",
584
+ color: row.status === import_resources.RESOURCE_STATUS_ENABLED ? "#067647" : "#667085"
585
+ }
586
+ },
587
+ statusLabel[row.status] ?? String(row.status)
588
+ )
589
+ ]),
590
+ (0, import_vue3.h)("td", { style: s.td }, [
591
+ (0, import_vue3.h)(
592
+ "button",
593
+ {
594
+ type: "button",
595
+ style: s.linkBtn,
596
+ onClick: () => openEdit(row)
597
+ },
598
+ "\u7F16\u8F91"
599
+ ),
600
+ (0, import_vue3.h)(
601
+ "button",
602
+ {
603
+ type: "button",
604
+ style: { ...s.linkBtn, color: "#d92d20" },
605
+ onClick: () => void handleDelete(row)
606
+ },
607
+ "\u5220\u9664"
608
+ )
609
+ ])
610
+ ])
611
+ )
612
+ )
613
+ ])
614
+ ]),
615
+ (0, import_vue3.h)("div", { style: s.pagination }, [
616
+ (0, import_vue3.h)("label", { style: s.pageSize }, [
617
+ "\u6BCF\u9875",
618
+ (0, import_vue3.h)(
619
+ "select",
620
+ {
621
+ style: s.select,
622
+ value: pageSize.value,
623
+ onChange: (e) => {
624
+ pageSize.value = e.target.value;
625
+ }
626
+ },
627
+ PAGE_SIZE_OPTIONS.map(
628
+ (size) => (0, import_vue3.h)("option", { key: size, value: size }, size)
629
+ )
630
+ )
631
+ ]),
632
+ (0, import_vue3.h)("div", { style: s.pageBtns }, [
633
+ (0, import_vue3.h)(
634
+ "button",
635
+ {
636
+ type: "button",
637
+ style: s.secondaryBtn,
638
+ disabled: !hasPreviousPage.value || loading.value,
639
+ onClick: () => void loadList("previous")
640
+ },
641
+ "\u4E0A\u4E00\u9875"
642
+ ),
643
+ (0, import_vue3.h)(
644
+ "button",
645
+ {
646
+ type: "button",
647
+ style: s.secondaryBtn,
648
+ disabled: !hasNextPage.value || loading.value,
649
+ onClick: () => void loadList("next")
650
+ },
651
+ "\u4E0B\u4E00\u9875"
652
+ )
653
+ ])
654
+ ]),
655
+ dialogOpen.value ? (0, import_vue3.h)(
656
+ "div",
657
+ { style: s.mask, onClick: closeDialog },
658
+ [
659
+ (0, import_vue3.h)(
660
+ "div",
661
+ {
662
+ style: s.dialog,
663
+ role: "dialog",
664
+ "aria-modal": "true",
665
+ onClick: (e) => e.stopPropagation()
666
+ },
667
+ [
668
+ (0, import_vue3.h)("div", { style: s.dialogHeader }, [
669
+ (0, import_vue3.h)(
670
+ "h3",
671
+ { style: s.dialogTitle },
672
+ editing.value ? "\u7F16\u8F91\u6743\u9650\u70B9" : "\u65B0\u589E\u6743\u9650\u70B9"
673
+ ),
674
+ (0, import_vue3.h)(
675
+ "button",
676
+ {
677
+ type: "button",
678
+ style: s.iconBtn,
679
+ "aria-label": "\u5173\u95ED",
680
+ onClick: closeDialog
681
+ },
682
+ "\xD7"
683
+ )
684
+ ]),
685
+ (0, import_vue3.h)(
686
+ "form",
687
+ {
688
+ style: s.form,
689
+ onSubmit: (e) => void handleSubmit(e)
690
+ },
691
+ [
692
+ (0, import_vue3.h)("label", { style: s.field }, [
693
+ (0, import_vue3.h)("span", { style: s.label }, "\u6743\u9650\u540D\u79F0"),
694
+ (0, import_vue3.h)("input", {
695
+ style: s.input,
696
+ value: form.name,
697
+ placeholder: "\u8BF7\u8F93\u5165\u6743\u9650\u540D\u79F0",
698
+ required: true,
699
+ onInput: (e) => {
700
+ form.name = e.target.value;
701
+ }
702
+ })
703
+ ]),
704
+ (0, import_vue3.h)("label", { style: s.field }, [
705
+ (0, import_vue3.h)("span", { style: s.label }, "\u63A5\u53E3\u6807\u8BC6"),
706
+ (0, import_vue3.h)("input", {
707
+ style: s.input,
708
+ value: form.identification,
709
+ placeholder: "\u5982 user:list",
710
+ required: true,
711
+ onInput: (e) => {
712
+ form.identification = e.target.value;
713
+ }
714
+ })
715
+ ]),
716
+ (0, import_vue3.h)("label", { style: s.field }, [
717
+ (0, import_vue3.h)("span", { style: s.label }, "\u72B6\u6001"),
718
+ (0, import_vue3.h)(
719
+ "select",
720
+ {
721
+ style: s.input,
722
+ value: form.status,
723
+ onChange: (e) => {
724
+ form.status = Number(
725
+ e.target.value
726
+ );
727
+ }
728
+ },
729
+ import_resources.RESOURCE_STATUS_OPTIONS.map(
730
+ (opt) => (0, import_vue3.h)("option", { key: opt.value, value: opt.value }, opt.label)
731
+ )
732
+ )
733
+ ]),
734
+ (0, import_vue3.h)("label", { style: s.field }, [
735
+ (0, import_vue3.h)("span", { style: s.label }, "\u79C1\u6709\u8D44\u6E90"),
736
+ (0, import_vue3.h)(
737
+ "select",
738
+ {
739
+ style: s.input,
740
+ value: form.private ? "1" : "0",
741
+ onChange: (e) => {
742
+ form.private = e.target.value === "1";
743
+ }
744
+ },
745
+ import_resources.RESOURCE_PRIVATE_OPTIONS.map(
746
+ (opt) => (0, import_vue3.h)(
747
+ "option",
748
+ {
749
+ key: String(opt.value),
750
+ value: opt.value ? "1" : "0"
751
+ },
752
+ opt.label
753
+ )
754
+ )
755
+ )
756
+ ]),
757
+ (0, import_vue3.h)("label", { style: s.field }, [
758
+ (0, import_vue3.h)("span", { style: s.label }, "\u63CF\u8FF0"),
759
+ (0, import_vue3.h)("textarea", {
760
+ style: {
761
+ ...s.input,
762
+ minHeight: "88px",
763
+ resize: "vertical"
764
+ },
765
+ value: form.description,
766
+ placeholder: "\u8BF7\u8F93\u5165\u63CF\u8FF0",
767
+ onInput: (e) => {
768
+ form.description = e.target.value;
769
+ }
770
+ })
771
+ ]),
772
+ (0, import_vue3.h)("div", { style: s.dialogFooter }, [
773
+ (0, import_vue3.h)(
774
+ "button",
775
+ {
776
+ type: "button",
777
+ style: s.secondaryBtn,
778
+ onClick: closeDialog
779
+ },
780
+ "\u53D6\u6D88"
781
+ ),
782
+ (0, import_vue3.h)(
783
+ "button",
784
+ {
785
+ type: "submit",
786
+ style: s.primaryBtn,
787
+ disabled: saving.value
788
+ },
789
+ saving.value ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58"
790
+ )
791
+ ])
792
+ ]
793
+ )
794
+ ]
795
+ )
796
+ ]
797
+ ) : null
798
+ ]);
799
+ }
800
+ });
801
+
227
802
  // src/vue/index.ts
228
803
  var import_core2 = require("../core");
804
+ var import_snowflake = require("../utils/snowflake");
805
+ var import_resources2 = require("../resources");
229
806
  // Annotate the CommonJS export names for ESM import in node:
230
807
  0 && (module.exports = {
231
808
  Can,
232
809
  PERMISSION_STORE_KEY,
233
810
  PermissionStore,
811
+ RESOURCE_PRIVATE_OPTIONS,
812
+ RESOURCE_STATUS_DISABLED,
813
+ RESOURCE_STATUS_ENABLED,
814
+ RESOURCE_STATUS_OPTIONS,
815
+ RESOURCE_TYPE_API,
816
+ ResourceManager,
817
+ appendQueryParam,
818
+ buildCreateBody,
819
+ buildUpdateBody,
820
+ createAuthorizationResourceApi,
821
+ createDefaultResourceRequest,
234
822
  createPermissionPlugin,
235
823
  createPermissionStore,
236
824
  createVPermission,
825
+ extractPagination,
826
+ extractRecords,
827
+ getAppClientId,
828
+ getDeviceWorkerId,
829
+ mapAuthorizationResource,
830
+ snowyflake,
237
831
  useHasPermission,
238
832
  useHasRole,
239
833
  usePermission