@yqg/permission 1.0.11 → 1.0.13

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yqg/permission",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "type": "module",
package/src/App.vue CHANGED
@@ -41,32 +41,30 @@ const changeLocale = () => {
41
41
  <yqg-permission
42
42
  :permissions="permissions"
43
43
  workNumber="05184"
44
- businessCode="CRANE"
45
44
  :color="color"
46
45
  :locale="locale"
47
46
  @onSuccess="() => {console.log('成功')}"
48
47
  >
49
48
  </yqg-permission>
50
49
  </div>
51
- <!-- <data class="case-card">
50
+ <data class="case-card">
52
51
  <div>2:文字组件</div>
53
52
  <yqg-permission
54
- :permissions="permissions"
55
- businessCode="CRANE"
53
+ :permissions="['ddd']"
56
54
  :color="color"
57
55
  workNumber="02124"
58
- type="text"
56
+ type="floatButton"
57
+ right="100px"
58
+ top="200px"
59
59
  >
60
60
  </yqg-permission>
61
61
  </data>
62
- -->
63
62
 
64
63
 
65
64
  <!-- <div class="case-card">
66
65
  <div>3:自定义</div>
67
66
  <yqg-permission
68
67
  :permissions="permissions"
69
- businessCode="CRANE"
70
68
  :color="color"
71
69
  workNumber="02124"
72
70
  locale="zh-CN"
Binary file
Binary file
@@ -18,7 +18,11 @@
18
18
  :label="t('applyPermission')"
19
19
  name="roleIds"
20
20
  :rules="[{ required: true, message: t('selectPlaceholder')}]">
21
+ <span v-if="!permissionList.length">
22
+ {{t('noPermissionTips')}}
23
+ </span>
21
24
  <CheckboxGroup
25
+ v-else
22
26
  v-model:value="formState.roleIds"
23
27
  style="display: block;"
24
28
  @change="onChangeHandler"
@@ -43,19 +47,9 @@
43
47
  }]">
44
48
  <Textarea
45
49
  v-model:value.trim="formState.applyReason"
46
- show-count
47
- :maxlength="300"
48
- :placeholder="t('applyReasonPlaceholder')"
50
+ :placeholder="t('applyReasonPlaceholder', {number: 300})"
49
51
  :auto-size="{ minRows: 2, maxRows: 5 }">
50
52
  </Textarea>
51
- <div style="margin-top: 4px;">
52
- <Tag
53
- :bordered="false"
54
- style="cursor: pointer;"
55
- v-for="item in reasons"
56
- @click="addReasonHandler(item)"
57
- :key="item">{{ item }}</Tag>
58
- </div>
59
53
  </FormItem>
60
54
 
61
55
  <FormItem :label="t('approvalProcess')">
@@ -82,7 +76,6 @@
82
76
  FormItem,
83
77
  CheckboxGroup,
84
78
  Textarea,
85
- Tag,
86
79
  message
87
80
  } from 'ant-design-vue';
88
81
  import SuccessModal from './success-modal.vue';
@@ -92,12 +85,6 @@
92
85
  import('./checkbox-item.vue')
93
86
  );
94
87
 
95
- const reasons = [
96
- t('applyReason1'),
97
- t('applyReason2'),
98
- t('applyReason3'),
99
- ]
100
-
101
88
  const props = defineProps({
102
89
  permissionList: {
103
90
  type: Array as () => PermissionType[],
@@ -132,18 +119,6 @@
132
119
  applyReason: '',
133
120
  submitWorkNumber: submitWorkNumber.value,
134
121
  });
135
-
136
- const addReasonHandler = (item: string) => {
137
- if (formState.applyReason.includes(item)) {
138
- return;
139
- }
140
- if (!formState.applyReason || formState.applyReason.endsWith('、')) {
141
- formState.applyReason += item;
142
- } else {
143
- formState.applyReason += `、${item}`;
144
- }
145
- formRef.value.validateFields(['applyReason']);
146
- }
147
122
 
148
123
  const handleOk = async() => {
149
124
  if (formState.roleIds.length > 5) {
@@ -8,7 +8,7 @@
8
8
  <Tag
9
9
  v-if="item.securityLevel"
10
10
  :bordered="false"
11
- :color="levelMap[item.securityLevel].color"
11
+ :style="{color: levelMap[item.securityLevel].color, background: levelMap[item.securityLevel].background}"
12
12
  class="crane-tag-position">
13
13
  {{ levelMap[item.securityLevel].text }}
14
14
  </Tag>
@@ -52,17 +52,15 @@
52
52
  <QuestionCircleOutlined class=" crane-week-color"/>
53
53
  </Popover>
54
54
 
55
- <Popover v-if="item.relatedDepartments">
55
+ <Popover v-if="item.relatedCompleteNames">
56
56
  <template #content>
57
57
  <div style="max-width: 400px;">
58
- {{t('adaptDepartment')}}:{{ item.relatedDepartments.map((item: any) => {
59
- return item.name;
60
- }).join('、') }}
58
+ {{t('adaptDepartment')}}:{{ item.relatedCompleteNames.join('、') }}
61
59
  </div>
62
60
  </template>
63
61
  <span class="crane-flex-center crane-margin-left-4">
64
62
  <img :src="departmentImg" height="14" width="14">
65
- <span class="crane-week-color crane-margin-left-4">{{ item.relatedDepartments.length }}</span>
63
+ <span class="crane-week-color crane-margin-left-4">{{ item.relatedCompleteNames.length }}</span>
66
64
  </span>
67
65
  </Popover>
68
66
 
@@ -88,16 +86,19 @@
88
86
 
89
87
  const levelMap:LevelMapType = {
90
88
  L1: {
91
- color: 'green',
92
- text: t('levels.L1')
89
+ color: '#1AA83B',
90
+ text: t('levels.L1'),
91
+ background: '#E3F9E9',
93
92
  },
94
93
  L2: {
95
- color: 'orange',
96
- text: t('levels.L2')
94
+ color: '#F37D1C',
95
+ text: t('levels.L2'),
96
+ background: '#FFE4BA'
97
97
  },
98
98
  L3: {
99
- color: 'red',
100
- text: t('levels.L3')
99
+ color: '#F2494B',
100
+ text: t('levels.L3'),
101
+ background: '#FDCDC5'
101
102
  },
102
103
  };
103
104
 
@@ -1,6 +1,5 @@
1
1
  <template>
2
2
  <ConfigProvider
3
- v-if="allPermissions.length"
4
3
  prefixCls="yqg-permission"
5
4
  :theme="{
6
5
  token: {
@@ -9,10 +8,22 @@
9
8
  }"
10
9
  >
11
10
  <div class="crane-wraper">
12
- <template v-if="type === 'text'">
13
- <TypographyLink @click="showModal" v-show="isShowText">{{t('permissionApply')}}</TypographyLink>
11
+ <template v-if="type === comType.FLOATBUTTON">
12
+ <FloatButton
13
+ ref="dragElement"
14
+ type="primary"
15
+ :tooltip="t('clickToApply')"
16
+ :style="{
17
+ right: RIGHT_DEFAULT,
18
+ top: currentTop,
19
+ }"
20
+ >
21
+ <template #icon>
22
+ <img :src="applyIconUrl" height="20" width="20"/>
23
+ </template>
24
+ </FloatButton>
14
25
  </template>
15
- <template v-else-if="type==='custom'">
26
+ <template v-else-if="type===comType.CUSTOM">
16
27
  <div @click="showModal">
17
28
  <slot name="custom"/>
18
29
  </div>
@@ -84,12 +95,14 @@
84
95
  </ConfigProvider>
85
96
  </template>
86
97
  <script lang="ts" setup>
87
- import { ref, defineAsyncComponent, computed, watchEffect, watch} from 'vue';
88
- import { Button, ConfigProvider, TypographyLink, Popover , message} from 'ant-design-vue';
98
+ import { ref, defineAsyncComponent, computed, watchEffect, watch } from 'vue';
99
+ import { Button, ConfigProvider, Popover , message, FloatButton} from 'ant-design-vue';
89
100
  import applyUrl from '@/assets/applying.png';
101
+ import applyIconUrl from '@/assets/applyicon.png';
90
102
  import noauthority from '@/assets/noauthority.png';
91
103
  import Http from '../axios/index';
92
104
  import t from '../utils';
105
+ import useDraggable from '../hooks/useDragable';
93
106
 
94
107
  const STATUS_MAP = {
95
108
  DEFAULT: 'DEFAULT',
@@ -97,6 +110,13 @@
97
110
  NO: 'NO',
98
111
  } as const;
99
112
 
113
+ const comType = {
114
+ FLOATBUTTON: 'floatButton',
115
+ DEFAULT: 'default',
116
+ CUSTOM: 'custom',
117
+ };
118
+ const RIGHT_DEFAULT = '10px';
119
+
100
120
  // 重置 message 类名,避免被全局样式覆盖
101
121
  message.config({prefixCls: 'yqg-permission-message'});
102
122
 
@@ -113,10 +133,6 @@
113
133
  type: [String, Array<String>],
114
134
  default: []
115
135
  },
116
- businessCode: {
117
- type: String,
118
- default: ''
119
- },
120
136
  locale: {
121
137
  type: String,
122
138
  default: 'zh-CN'
@@ -129,8 +145,12 @@
129
145
  type: String,
130
146
  default: 'default'
131
147
  },
148
+ top: {
149
+ type: String,
150
+ default: '100px'
151
+ }
132
152
  });
133
-
153
+
134
154
  const open = ref(false);
135
155
  const curApproving = ref<PermissionType>();
136
156
  let permissionList = ref<PermissionListType>([]);
@@ -138,25 +158,27 @@
138
158
  imageUrl: noauthority,
139
159
  status: '',
140
160
  })
141
-
161
+
142
162
  const allPermissions = computed(() => {
163
+ permissionList.value = [];
143
164
  if (Array.isArray(props.permissions)) {
144
- return props.permissions;
165
+ return props.permissions.filter((item) => item.trim());
145
166
  }
146
-
147
- return props.permissions.split(',');
167
+ return props.permissions?.split(',')?.filter((item) => item.trim()) || [];
148
168
  });
149
169
 
150
- const isShowText = computed(() => {
151
- // 所有权限点的状态要么是NO,要么是OWNER,那么不显示文字组件
152
- return !permissionList.value.every((item) => item.businessApplyType === 'NO' || item.businessApplyType === 'OWNER');
153
-
154
- });
170
+ const businessCode = computed(() => {
171
+ const code = allPermissions.value[0] || '';
172
+ if (!code) return '';
173
+
174
+ return code.split('.')[0];
175
+ })
155
176
 
156
177
  const formatPermissionsData = (data: PermissionListType) => {
157
178
  const arr:PermissionListType = [];
158
179
  const flattenData = (list: PermissionListType) => {
159
180
  list.forEach((item) => {
181
+ item.name = item.name.replace(/^[^.]+\./, '');
160
182
  if (item.children) {
161
183
  flattenData(item.children);
162
184
  } else {
@@ -224,13 +246,11 @@
224
246
  };
225
247
 
226
248
  const getPermissions = async () => {
227
- const { businessCode, workNumber } = props;
249
+ const { workNumber } = props;
228
250
  const permissions = allPermissions.value;
229
-
230
- if (!permissions?.length || !businessCode || !workNumber) return;
251
+ if (!permissions?.length || !workNumber) return;
231
252
 
232
253
  const params = {
233
- businessCode,
234
254
  workNumber,
235
255
  features: permissions.toString(),
236
256
  };
@@ -246,6 +266,8 @@
246
266
  open.value = !open.value;
247
267
  };
248
268
 
269
+ const { currentTop, dragElement } = useDraggable(props, showModal);
270
+
249
271
  watchEffect(getPermissions);
250
272
 
251
273
  watch(() => props.locale, (cur, pre) => {
@@ -270,3 +292,4 @@
270
292
  }
271
293
  </style>
272
294
 
295
+ ../hooks/useDragable
@@ -0,0 +1,135 @@
1
+ // useDraggable.js
2
+
3
+ import { ref, onBeforeUnmount, watch, onMounted } from 'vue';
4
+
5
+ export default function useDraggable(props: { top: any }, showModal: () => void) {
6
+ const currentTop = ref(0);
7
+ const isDragging = ref(false); // 是否正在拖拽
8
+ const startX = ref(0); // 鼠标按下时的X坐标
9
+ const initialX = ref(0); // 元素初始X坐标
10
+ const initialY = ref(0);
11
+ const dragElement = ref<any>(null);
12
+
13
+ watch(() => props.top, (newVal) => {
14
+ currentTop.value = newVal;
15
+ }, { immediate: true });
16
+
17
+ // 获取元素的初始位置
18
+ const getPosition = (el: HTMLElement) => {
19
+ const rect = el.getBoundingClientRect();
20
+ return {
21
+ x: rect.left,
22
+ y: rect.top
23
+ };
24
+ };
25
+
26
+ // 限制拖拽元素在屏幕内
27
+ const constrainToScreen = (clientX: number, clientY: number, el: HTMLElement) => {
28
+ const { innerWidth, innerHeight } = window;
29
+ const elRect = el.getBoundingClientRect();
30
+
31
+ const constrainedX = Math.min(Math.max(clientX, 0), innerWidth - elRect.width);
32
+ const constrainedY = Math.min(Math.max(clientY, 0), innerHeight - elRect.height);
33
+
34
+ return { x: constrainedX, y: constrainedY };
35
+ };
36
+
37
+ // 鼠标移动时的处理函数
38
+ const onMouseMove = (e: MouseEvent, el: HTMLElement) => {
39
+ if (!isDragging.value) return;
40
+
41
+ // 移动的时候yqg-permission-tooltip隐藏
42
+ const tooltip = document.querySelector('.yqg-permission-tooltip') as HTMLElement;
43
+ if (tooltip) {
44
+ tooltip.style.display = 'none';
45
+ }
46
+
47
+ const { clientX, clientY } = e;
48
+ const { x, y } = constrainToScreen(clientX - startX.value + initialX.value, clientY - currentTop.value + initialY.value, el);
49
+
50
+ el.style.left = `${x}px`;
51
+ el.style.top = `${y}px`;
52
+
53
+ };
54
+
55
+ // 鼠标松开时的处理函数
56
+ const onMouseUp = (e: MouseEvent, el: HTMLElement) => {
57
+ if (!isDragging.value) return;
58
+
59
+ // 阻止点击事件触发
60
+ e.preventDefault(); // 阻止默认行为
61
+ e.stopPropagation(); // 阻止事件冒泡
62
+
63
+ // // 获取元素当前的位置
64
+ const { x: currentX, y: currentY } = getPosition(el);
65
+ if ( Math.abs(currentY - initialY.value) < 10 && Math.abs(currentX - initialX.value) < 10) {
66
+ showModal();
67
+ // 卸载拖拽
68
+ isDragging.value = false;
69
+
70
+ return;
71
+ }
72
+
73
+
74
+ isDragging.value = false;
75
+ const { clientY } = e;
76
+
77
+ // 在鼠标松开时设置x为初始位置,y为鼠标当前位置
78
+ const { x, y } = constrainToScreen(initialX.value, clientY - currentTop.value + initialY.value, el);
79
+ el.style.transition = 'all 0.3s';
80
+ el.style.left = `${x}px`;
81
+ el.style.top = `${y}px`;
82
+
83
+ // 清除事件监听
84
+ document.removeEventListener('mousemove', (e) => onMouseMove(e, el));
85
+ document.removeEventListener('mouseup', (e) => onMouseUp(e, el));
86
+ };
87
+
88
+ // 鼠标按下时的处理函数
89
+ const onMouseDown = (e: MouseEvent, el: HTMLElement) => {
90
+ isDragging.value = true;
91
+
92
+ // 阻止点击事件触发
93
+ e.preventDefault(); // 阻止默认行为
94
+ e.stopPropagation();
95
+
96
+ // 获取鼠标按下时的位置
97
+ startX.value = e.clientX;
98
+ currentTop.value = e.clientY;
99
+
100
+
101
+ // 获取元素的初始位置
102
+ const { x, y } = getPosition(el);
103
+ initialX.value = x;
104
+ initialY.value = y;
105
+ el.style.transition = 'none';
106
+
107
+ // 添加鼠标移动和鼠标松开事件监听
108
+ document.addEventListener('mousemove', (e) => onMouseMove(e, el));
109
+ document.addEventListener('mouseup', (e) => onMouseUp(e, el));
110
+ };
111
+
112
+ // 返回拖拽的绑定方法
113
+ const bindDraggable = () => {
114
+ onMounted(() => {
115
+ const el = dragElement.value?.$el;
116
+ if (el) {
117
+ el.addEventListener('mousedown', (e: MouseEvent) => onMouseDown(e, el));
118
+ }
119
+ });
120
+
121
+ onBeforeUnmount(() => {
122
+ const el = dragElement.value?.$el;
123
+ if (el) {
124
+ el.removeEventListener('mousedown', (e: MouseEvent) => onMouseDown(e, el));
125
+ }
126
+ });
127
+ };
128
+
129
+ bindDraggable();
130
+
131
+ return {
132
+ currentTop,
133
+ dragElement,
134
+ };
135
+ }
package/src/i18n/en-US.ts CHANGED
@@ -3,35 +3,34 @@ export default {
3
3
  applyPermission: '申请权限',
4
4
  applyReason: '申请理由',
5
5
  approvalProcess: '审批流程',
6
- applyReason1: '新入职员工申请',
7
- applyReason2: '项目需要',
8
- applyReason3: '数据查询与分析',
9
6
  applyReasonPlaceholder: '请尽可能详细描述申请理由',
10
7
  cancel: '取消',
11
8
  submit: '确定',
12
9
  close: '关闭',
13
10
  viewApprovalDetail: '查看审批详情',
14
- applyMore: '继续申请其他权限',
11
+ applyMore: '继续申请其他权限',
15
12
  successTips: '已提交申请,审批通过后可拥有相关权限',
16
13
  resoultTitle: '操作结果反馈',
17
14
  start: '发起',
18
15
  end: '结束',
19
- noNeed: '无需审批',
16
+ noNeed: '无需审批',
20
17
  adaptDepartment: '适用部门',
21
- noApprovalProcess: '无审批流程',
18
+ noApprovalProcess: '无审批流程',
22
19
  excessTips: '一次最多可申请{number}个权限',
23
20
  unavailableTips: '您暂无权限查看/操作该页面,请点击下方按钮进行申请',
24
21
  appliedTips: '权限已申请,正在{status}...',
25
22
  unapplyTips: '您暂无权限查看/操作该页面,且该页面中没有您可以申请的权限,',
26
- callManager: '如有需要请联系系统管理员',
27
- manager: '系统管理员',
23
+ callManager: '如有需要请联系系统管理员',
24
+ manager: '系统管理员',
28
25
  availableTime: '有效期',
29
- selectPlaceholder: '请选择权限点',
30
- reasonPlaceholder: '请输入申请理由',
31
- maxCountTips: '一次最多只可申请{count}个权限',
32
- maxLengthTips: '最多{length}个字符',
33
- lastDays: '{count}天后到期',
34
- taday: '今天到期',
26
+ selectPlaceholder: '请选择权限点',
27
+ reasonPlaceholder: '请输入申请理由',
28
+ maxCountTips: '一次最多只可申请{count}个权限',
29
+ maxLengthTips: '最多{length}个字符',
30
+ lastDays: '{count}天后到期',
31
+ taday: '今天到期',
32
+ clickToApply: '点击申请菜单',
33
+ noPermissionTips: '该菜单下暂无权限点',
35
34
  availiables: {
36
35
  SEVEN_DAYS: '7天',
37
36
  THIRTY_DAYS: '30天',
@@ -48,10 +47,10 @@ export default {
48
47
  PENDING: '审批中',
49
48
  NO: '不可申请',
50
49
  OWNER: '永久拥有',
51
- TEMP_OWNER: '临时拥有',
50
+ TEMP_OWNER: '临时拥有',
52
51
  },
53
- operationType: {
54
- QUERY: '查询',
55
- MANAGE: '操作',
56
- }
52
+ operationType: {
53
+ QUERY: '查询',
54
+ MANAGE: '操作',
55
+ }
57
56
  };
package/src/i18n/zh-CH.ts CHANGED
@@ -3,10 +3,7 @@ export default {
3
3
  applyPermission: '申请权限',
4
4
  applyReason: '申请理由',
5
5
  approvalProcess: '审批流程',
6
- applyReason1: '新入职员工申请',
7
- applyReason2: '项目需要',
8
- applyReason3: '数据查询与分析',
9
- applyReasonPlaceholder: '请尽可能详细描述申请理由',
6
+ applyReasonPlaceholder: '请尽可能详细描述申请理由({number}字以内)',
10
7
  cancel: '取消',
11
8
  submit: '确定',
12
9
  close: '关闭',
@@ -32,6 +29,8 @@ export default {
32
29
  maxLengthTips: '最多{length}个字符',
33
30
  lastDays: '{count}天后到期',
34
31
  taday: '今天到期',
32
+ clickToApply: '点击申请权限',
33
+ noPermissionTips: '该菜单下暂无权限点',
35
34
  availiables: {
36
35
  SEVEN_DAYS: '7天',
37
36
  THIRTY_DAYS: '30天',
@@ -21,6 +21,7 @@ declare type PermissionType = {
21
21
  operationType: string;
22
22
  securityLevel: LevelType;
23
23
  relatedDepartments?: any[];
24
+ relatedCompleteNames: string[];
24
25
  relatedDepartmentIds?: number[];
25
26
  curDepartmentId?: number;
26
27
  businessApplyType: StatusType;
@@ -35,6 +36,7 @@ declare type LevelMapType = {
35
36
  [key in LevelType]: {
36
37
  color: string;
37
38
  text: string;
39
+ background: string;
38
40
  };
39
41
  };
40
42