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