@pubinfo/module-rbac 2.0.0-rc.5 → 2.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.
package/dist/index.js CHANGED
@@ -75,9 +75,9 @@ import './index.css';var We = {
75
75
  "src/views/page_w_setting/index.vue": () => import("./page_w_setting-B_im6vBo.js"),
76
76
  "src/views/position/index.vue": () => import("./position-BkpbHXYP.js"),
77
77
  "src/views/region/index.vue": () => import("./region-DVkbjI9t.js"),
78
- "src/views/resource/index.vue": () => import("./resource-CyI9ZpmF.js"),
79
- "src/views/role/index.vue": () => import("./role-B2tKqUvP.js"),
78
+ "src/views/resource/index.vue": () => import("./resource-Bzx2Tx8m.js"),
80
79
  "src/views/role_group/index.vue": () => import("./role_group-DqzFHwKx.js"),
80
+ "src/views/role/index.vue": () => import("./role-B2tKqUvP.js"),
81
81
  "src/views/safe_setting/index.vue": () => import("./safe_setting-uj9p_wW0.js"),
82
82
  "src/views/tabbar_setting/index.vue": () => import("./tabbar_setting-HFHrLVgt.js"),
83
83
  "src/views/tenant/index.vue": () => import("./tenant-C8kVbfgt.js"),
@@ -89,10 +89,10 @@ import './index.css';var We = {
89
89
  "src/views/data-permission/components/createAndEditDataPermission.vue": () => import("./createAndEditDataPermission-CAaxueTy.js"),
90
90
  "src/views/dictionary/components/drawerDictionary.vue": () => import("./drawerDictionary-Bk0BgL7i.js"),
91
91
  "src/views/dictionary/components/drawerDictionaryItem.vue": () => import("./drawerDictionaryItem-Dy2T56AH.js"),
92
- "src/views/group/components/drawerGroup.vue": () => import("./drawerGroup-ZyzAWXOl.js"),
93
92
  "src/views/log_center/components/browserType.vue": () => import("./browserType-BGl2j5RW.js"),
94
93
  "src/views/log_center/components/loginHistoryDetail.vue": () => import("./loginHistoryDetail-DiuNa6Sv.js"),
95
94
  "src/views/log_center/components/operateHistoryDetail.vue": () => import("./operateHistoryDetail-r30ZBNqw.js"),
95
+ "src/views/group/components/drawerGroup.vue": () => import("./drawerGroup-ZyzAWXOl.js"),
96
96
  "src/views/organization/components/drawerOrganization.vue": () => import("./drawerOrganization-HSVB8JzO.js"),
97
97
  "src/views/organization/components/drawerRole.vue": () => import("./drawerRole-BVeaz3Yb.js"),
98
98
  "src/views/position/components/drawerPosition.vue": () => import("./drawerPosition-vsuG4JYe.js"),
@@ -100,15 +100,15 @@ import './index.css';var We = {
100
100
  "src/views/resource/components/ComponentSelect.vue": () => import("./ComponentSelect-Bhwuc86o.js"),
101
101
  "src/views/resource/components/DynamicRoutesForm.vue": () => import("./DynamicRoutesForm-D35jFnxF.js"),
102
102
  "src/views/resource/components/HoverCard.vue": () => import("./HoverCard-U5WTpvFy.js"),
103
- "src/views/resource/components/IconSelect.vue": () => import("./IconSelect-Ct5FkeHI.js"),
103
+ "src/views/resource/components/IconSelect.vue": () => import("./IconSelect-BEetYi8i.js"),
104
104
  "src/views/resource/components/ImportExport.vue": () => import("./ImportExport-D8uzaOMz.js"),
105
105
  "src/views/resource/components/MetaForm.vue": () => import("./MetaForm-BSGuZXgj.js"),
106
- "src/views/resource/components/ResourceEdit.vue": () => import("./ResourceEdit-oAPLPUf0.js"),
106
+ "src/views/resource/components/ResourceEdit.vue": () => import("./ResourceEdit-JPc5dCoU.js"),
107
107
  "src/views/resource/components/RoleRelation.vue": () => import("./RoleRelation-YaSQQxQ2.js"),
108
- "src/views/role/components/ResourceRelation.vue": () => import("./ResourceRelation-BRseTUw2.js"),
109
- "src/views/role/components/drawerRole.vue": () => import("./drawerRole-tan379DU.js"),
110
108
  "src/views/role_group/components/ResourceRelation.vue": () => import("./ResourceRelation-CKolCnHC.js"),
111
109
  "src/views/role_group/components/drawerRole.vue": () => import("./drawerRole-CzTW_I2H.js"),
110
+ "src/views/role/components/ResourceRelation.vue": () => import("./ResourceRelation-BRseTUw2.js"),
111
+ "src/views/role/components/drawerRole.vue": () => import("./drawerRole-tan379DU.js"),
112
112
  "src/views/tenant/components/TenantEdit.vue": () => import("./TenantEdit-C28473_2.js"),
113
113
  "src/views/user/components/OrgAndPosition.vue": () => import("./OrgAndPosition-CF7ZJtNB.js"),
114
114
  "src/views/user/components/UserAuthorization.vue": () => import("./UserAuthorization-C4SLMNmh.js"),
@@ -1413,7 +1413,7 @@ const rf = {
1413
1413
  children: [
1414
1414
  {
1415
1415
  path: "resource",
1416
- component: () => import("./resource-CyI9ZpmF.js"),
1416
+ component: () => import("./resource-Bzx2Tx8m.js"),
1417
1417
  name: "Resource",
1418
1418
  meta: {
1419
1419
  title: "资源管理",
@@ -6,11 +6,11 @@ import "./enum-CYW8g64p.js";
6
6
  import { b as r, c as i, d as a, e as o } from "./enum-BMY6bmPA.js";
7
7
  import "./DynamicRoutesForm-CE2RPs7y.js";
8
8
  import "./HoverCard-B79q5sly.js";
9
- import "./IconSelect-HAhfS6hd.js";
9
+ import "./IconSelect-D50456Yh.js";
10
10
  import "./dayjs.min-CdDcH50N.js";
11
11
  import { b as s } from "./ImportExport-ByRTssxP.js";
12
12
  import "./MetaForm-DErrpELP.js";
13
- import { b as c } from "./ResourceEdit-DF-2_zoi.js";
13
+ import { b as c } from "./ResourceEdit-BVdRFGOK.js";
14
14
  import { b as l } from "./RoleRelation-DXZxscPY.js";
15
15
  import { PubinfoIcon as u, useAuth as d } from "pubinfo";
16
16
  import { computed as f, createBlock as p, createCommentVNode as m, createElementBlock as h, createElementVNode as g, createTextVNode as _, createVNode as v, defineComponent as y, openBlock as b, ref as x, resolveDirective as S, toDisplayString as C, unref as w, withCtx as T, withDirectives as E } from "vue";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pubinfo/module-rbac",
3
3
  "type": "module",
4
- "version": "2.0.0-rc.5",
4
+ "version": "2.0.1",
5
5
  "exports": {
6
6
  ".": {
7
7
  "types": "./dist/index.d.ts",
@@ -24,7 +24,7 @@
24
24
  "@pubinfo/pro-components": "^1.7.3",
25
25
  "alova": "^3.3.4",
26
26
  "ant-design-vue": "^4.2.6",
27
- "pubinfo": "2.0.0-rc.5"
27
+ "pubinfo": "2.0.1"
28
28
  },
29
29
  "dependencies": {
30
30
  "@destyler/color-picker": "^0.1.0",
@@ -48,7 +48,7 @@
48
48
  "alova": "^3.3.4",
49
49
  "ant-design-vue": "^4.2.6",
50
50
  "type-fest": "^4.41.0",
51
- "pubinfo": "2.0.0-rc.5"
51
+ "pubinfo": "2.0.1"
52
52
  },
53
53
  "scripts": {
54
54
  "dev": "pubinfo build -w --sourcemap",
@@ -358,58 +358,63 @@ const previewBoxPadding = 4; // 与 shapeBoxDefaults 中的 padding 对齐
358
358
  <!-- 图标颜色设置:始终显示;非 AntD 图标时禁用 -->
359
359
  <div class="flex items-center gap-3 w-full">
360
360
  <label class="text-12px opacity-70 w-14 shrink-0">图标色</label>
361
- <a-input
362
- v-model:value="iconColor"
363
- allow-clear
364
- :placeholder="boxType === 'null' ? '默认' : '#ffffff'"
365
- size="small"
366
- class="flex-1 min-w-0"
367
- :disabled="!isAntdIcon"
368
- >
369
- <template #prefix>
370
- <div class="relative inline-flex items-center">
371
- <button
372
- type="button"
373
- :disabled="!isAntdIcon"
374
- class="w-4 h-4 rounded border border-gray-300 dark:border-gray-700"
375
- :class="!isAntdIcon ? 'opacity-50 cursor-not-allowed' : ''"
376
- :style="{ background: iconColor || '#ffffff' }"
377
- @click="openIconColorPicker"
378
- />
379
- <input
380
- ref="iconColorPickerRef"
381
- type="color"
382
- :value="iconColor || '#ffffff'"
383
- :disabled="!isAntdIcon"
384
- class="absolute left-0 top-0 opacity-0 pointer-events-none"
385
- style="width:16px;height:16px;"
386
- @input="iconColor = ($event.target as HTMLInputElement).value"
387
- >
388
- </div>
389
- </template>
390
- </a-input>
361
+ <div class="flex flex-col">
362
+ <a-input
363
+ v-model:value="iconColor"
364
+ allow-clear
365
+ :placeholder="boxType === 'null' ? '默认' : '#ffffff'"
366
+ size="small"
367
+ class="flex-1 min-w-0"
368
+ :disabled="!isAntdIcon"
369
+ >
370
+ <template #prefix>
371
+ <div class="relative inline-flex items-center">
372
+ <button
373
+ type="button"
374
+ :disabled="!isAntdIcon"
375
+ class="w-4 h-4 rounded border border-gray-300 dark:border-gray-700"
376
+ :class="!isAntdIcon ? 'opacity-50 cursor-not-allowed' : ''"
377
+ :style="{ background: iconColor || '#ffffff' }"
378
+ @click="openIconColorPicker"
379
+ />
380
+ <input
381
+ ref="iconColorPickerRef"
382
+ type="color"
383
+ :value="iconColor || '#ffffff'"
384
+ :disabled="!isAntdIcon"
385
+ class="absolute left-0 top-0 opacity-0 pointer-events-none"
386
+ style="width:16px;height:16px;"
387
+ @input="iconColor = ($event.target as HTMLInputElement).value"
388
+ >
389
+ </div>
390
+ </template>
391
+ </a-input>
392
+ <span v-if="!isAntdIcon" class="text-8px opacity-70">仅 Ant Design 图标有效</span>
393
+ </div>
391
394
  </div>
392
395
  </div>
393
396
  <!-- 预览:固定底部 -->
394
- <div class="w-full mt-auto">
395
- <div class="py-4 rounded-md border-t border-t-dashed border-t-[#d0d7de] dark:border-t-[#30363d] flex flex-col items-center gap-2">
397
+ <div class="w-full mt-auto flex aspect-square">
398
+ <div class="flex-1 w-full h-full py-4 rounded-md border-t border-t-dashed border-t-[#d0d7de] dark:border-t-[#30363d] flex flex-col items-center gap-2">
396
399
  <template v-if="tempValueRef">
397
- <PubinfoIcon
398
- v-if="boxType === 'null'"
399
- :name="tempValueRef"
400
- :size="80"
401
- :color="(isAntdIcon && iconColor) ? iconColor : undefined"
402
- />
403
- <PubinfoIcon
404
- v-else
405
- :name="tempValueRef"
406
- :box="boxType"
407
- :size="80"
408
- :angle="boxAngle"
409
- :background="boxBackground"
410
- :radius="boxRadius"
411
- :color="isAntdIcon ? (iconColor || '#ffffff') : undefined"
412
- />
400
+ <div class="w-full h-full flex items-center justify-center">
401
+ <PubinfoIcon
402
+ v-if="boxType === 'null'"
403
+ :name="tempValueRef"
404
+ :size="80"
405
+ :color="(isAntdIcon && iconColor) ? iconColor : undefined"
406
+ />
407
+ <PubinfoIcon
408
+ v-else
409
+ :name="tempValueRef"
410
+ :box="boxType"
411
+ :size="80"
412
+ :angle="boxAngle"
413
+ :background="boxBackground"
414
+ :radius="boxRadius"
415
+ :color="isAntdIcon ? (iconColor || '#ffffff') : undefined"
416
+ />
417
+ </div>
413
418
  </template>
414
419
  </div>
415
420
  </div>
@@ -17,32 +17,77 @@ const modelValue = defineModel<Form>({
17
17
  },
18
18
  });
19
19
 
20
- // 将外部存储扩展到 meta.iconOptions,避免破坏后端接口的 `icon: string` 结构
21
- const iconOptions = computed({
22
- get() {
23
- const meta = (modelValue.value.meta as any) || ((modelValue.value.meta as any) = {});
24
- if (!meta.iconOptions) {
25
- meta.iconOptions = {
26
- boxType: 'null',
27
- angle: 65,
28
- background: { from: '#65E54A', to: '#35C724' },
29
- radius: 6,
30
- iconColor: '',
31
- };
20
+ // 仅当选择了非空的 boxType 时才把 iconOptions 持久化到 meta.iconOptions
21
+ // 避免未选择边框模式时仍写入多余数据导致后端解析问题。
22
+ interface LocalIconOptions {
23
+ boxType: 'null' | 'square' | 'prism'
24
+ angle: number
25
+ background: { from: string, to: string } | string
26
+ radius: number
27
+ iconColor: string
28
+ }
29
+
30
+ function createDefaultIconOptions(): LocalIconOptions {
31
+ return {
32
+ boxType: 'null',
33
+ angle: 65,
34
+ background: { from: '#65E54A', to: '#35C724' },
35
+ radius: 6,
36
+ iconColor: '',
37
+ };
38
+ }
39
+
40
+ const metaRef = computed(() => (modelValue.value.meta as any) || ((modelValue.value.meta as any) = {}));
41
+
42
+ // 本地响应式副本,解决:刷新后后端异步填充 meta.iconOptions(对象引用被整体替换)导致视图仍指向初始默认对象的问题。
43
+ const iconOptions = reactive<LocalIconOptions>(createDefaultIconOptions());
44
+
45
+ // 监听 meta.iconOptions 的“引用”变化(后端数据覆盖时)并合并到本地副本;
46
+ // 不用 deep 避免属性级别循环触发。
47
+ watch(
48
+ () => metaRef.value.iconOptions,
49
+ (val) => {
50
+ if (val) {
51
+ Object.assign(iconOptions, createDefaultIconOptions(), val);
52
+ }
53
+ else {
54
+ // 若后端未提供,重置为默认值
55
+ Object.assign(iconOptions, createDefaultIconOptions());
32
56
  }
33
- return meta.iconOptions;
34
57
  },
35
- set(val) {
36
- const meta = (modelValue.value.meta as any) || ((modelValue.value.meta as any) = {});
37
- meta.iconOptions = val || {
38
- boxType: 'null',
39
- angle: 65,
40
- background: { from: '#65E54A', to: '#35C724' },
41
- radius: 6,
42
- iconColor: '',
43
- };
58
+ { immediate: true },
59
+ );
60
+
61
+ // 将本地修改“写回” meta.iconOptions,使用浅比较避免无限循环。
62
+ watch(
63
+ iconOptions,
64
+ (val) => {
65
+ if (!modelValue.value.icon) {
66
+ if (metaRef.value.iconOptions) {
67
+ Reflect.deleteProperty(metaRef.value, 'iconOptions');
68
+ }
69
+ return;
70
+ }
71
+ const current = metaRef.value.iconOptions;
72
+ let changed = false;
73
+ if (!current) {
74
+ changed = true;
75
+ }
76
+ else {
77
+ const keys = new Set([...Object.keys(current), ...Object.keys(val as any)]);
78
+ for (const k of keys) {
79
+ if ((current as any)[k] !== (val as any)[k]) {
80
+ changed = true;
81
+ break;
82
+ }
83
+ }
84
+ }
85
+ if (changed) {
86
+ metaRef.value.iconOptions = { ...(val as any) };
87
+ }
44
88
  },
45
- });
89
+ { deep: true },
90
+ );
46
91
 
47
92
  const show = computed(() => {
48
93
  const type = modelValue.value.type as RESOURCE_TYPE;
@@ -61,13 +106,14 @@ const isDynamicRoutesForm = computed(() => {
61
106
  function clearIcon(e: MouseEvent) {
62
107
  e.stopPropagation();
63
108
  if (modelValue.value.icon) {
64
- modelValue.value.icon = undefined; // 设为空串以触发 v-if 切换
109
+ modelValue.value.icon = undefined; // 设为 undefined 以触发 v-if 切换
110
+ Reflect.deleteProperty(metaRef.value, 'iconOptions');
65
111
  }
66
112
  }
67
113
  </script>
68
114
 
69
115
  <template>
70
- <div v-if="isDynamicRoutesForm && show.icon" class="w-full h-full flex justify-center mb-4">
116
+ <a-form-item v-if="isDynamicRoutesForm && show.icon" label="资源图标">
71
117
  <ResourceIconesSelect
72
118
  v-slot="{ open }"
73
119
  v-model="modelValue.icon"
@@ -81,17 +127,17 @@ function clearIcon(e: MouseEvent) {
81
127
  <template v-if="modelValue.icon">
82
128
  <!-- 已选择图标展示盒子 -->
83
129
  <div
84
- class="size-20 flex justify-center items-center cursor-pointer
130
+ class="size-64px flex justify-center items-center cursor-pointer
85
131
  rounded-md border-px border-dashed relative group
86
132
  border-[#d9d9d9] dark:border-[#424242]
87
- hover:border-[#5794f7] dark:hover:border-[#5187e1]"
133
+ hover:border-[#5794f7] dark:hover:border-[#5187e1] p-8px"
88
134
  @click="open"
89
135
  >
90
136
  <PubinfoIcon
91
137
  v-if="iconOptions.boxType && iconOptions.boxType !== 'null'"
92
138
  :name="modelValue.icon"
93
139
  :box="iconOptions.boxType"
94
- :size="76"
140
+ size="48px"
95
141
  :radius="iconOptions.radius"
96
142
  :background="iconOptions.background"
97
143
  :angle="iconOptions.angle"
@@ -100,7 +146,7 @@ function clearIcon(e: MouseEvent) {
100
146
  <PubinfoIcon
101
147
  v-else
102
148
  :name="modelValue.icon"
103
- size="76px"
149
+ size="48px"
104
150
  :color="(modelValue.icon || '').startsWith('antd:') ? (iconOptions.iconColor || undefined) : undefined"
105
151
  />
106
152
  <!-- 清除按钮 -->
@@ -118,7 +164,7 @@ function clearIcon(e: MouseEvent) {
118
164
  <!-- null icon select box -->
119
165
  <template v-else>
120
166
  <div
121
- class="size-20 flex justify-center items-center
167
+ class="size-64px flex justify-center items-center
122
168
  rounded-md border-px border-dashed cursor-pointer
123
169
  border-[#d9d9d9] dark:border-[#424242]
124
170
  hover:border-[#5794f7] dark:hover:border-[#5187e1]
@@ -134,5 +180,5 @@ function clearIcon(e: MouseEvent) {
134
180
  </div>
135
181
  </template>
136
182
  </ResourceIconesSelect>
137
- </div>
183
+ </a-form-item>
138
184
  </template>
@@ -203,42 +203,40 @@ defineExpose({
203
203
  :label-col="{ style: { width: '100px' } }"
204
204
  >
205
205
  <a-row :gutter="8">
206
- <a-col :span="12">
207
- <a-col v-if="parentNode?.name" :span="24">
208
- <a-form-item name="parentId">
209
- <template #label>
210
- <DatabaseOutlined class="mr-1" />
211
- 父资源
212
- </template>
213
- {{ parentNode?.name }}
214
- </a-form-item>
215
- </a-col>
216
- <a-col :span="24">
217
- <a-form-item label="资源类型" name="type">
218
- <div
219
- v-if="state.title === ACTION.EDIT"
220
- class="flex items-center space-x-1"
221
- >
222
- <!-- <PubinfoIcon v-if="form.type" :name="`resource-${RESOURCE_ICON[Number(form.type)]}`" class="text-xl" />
206
+ <a-col v-if="parentNode?.name" :span="24">
207
+ <a-form-item name="parentId">
208
+ <template #label>
209
+ <DatabaseOutlined class="mr-1" />
210
+ 父资源
211
+ </template>
212
+ {{ parentNode?.name }}
213
+ </a-form-item>
214
+ </a-col>
215
+ <a-col :span="24">
216
+ <a-form-item label="资源类型" name="type">
217
+ <div
218
+ v-if="state.title === ACTION.EDIT"
219
+ class="flex items-center space-x-1"
220
+ >
221
+ <!-- <PubinfoIcon v-if="form.type" :name="`resource-${RESOURCE_ICON[Number(form.type)]}`" class="text-xl" />
223
222
  <span>
224
223
  {{ resourceComputedOptions.find(e => e.value === form.type)?.label }}
225
224
  </span> -->
226
225
 
227
- <a-tag v-if="form.type" :color="RESOURCE_COLOR[Number(form.type)]" :bordered="false">
228
- {{ resourceComputedOptions.find(e => e.value === form.type)?.label }}
229
- </a-tag>
230
- </div>
231
- <a-radio-group
232
- v-else
233
- v-model:value="form.type"
234
- :options="resourceComputedOptions"
235
- option-type="button"
236
- button-style="solid"
237
- />
238
- </a-form-item>
239
- </a-col>
226
+ <a-tag v-if="form.type" :color="RESOURCE_COLOR[Number(form.type)]" :bordered="false">
227
+ {{ resourceComputedOptions.find(e => e.value === form.type)?.label }}
228
+ </a-tag>
229
+ </div>
230
+ <a-radio-group
231
+ v-else
232
+ v-model:value="form.type"
233
+ :options="resourceComputedOptions"
234
+ option-type="button"
235
+ button-style="solid"
236
+ />
237
+ </a-form-item>
240
238
  </a-col>
241
- <a-col :span="12">
239
+ <a-col :span="24">
242
240
  <ResourceIconSelect v-model="form" />
243
241
  </a-col>
244
242
  </a-row>