@yqg/permission 1.2.1 → 1.3.0-alpha.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.
Files changed (36) hide show
  1. package/README.md +50 -38
  2. package/dist/apply-modal-CpmDDWWV.js +12865 -0
  3. package/dist/category-selector-BQ0-kg3o.js +1275 -0
  4. package/dist/index-D_0ZQip-.js +2972 -0
  5. package/dist/index-wLkVeDMW.js +5040 -0
  6. package/dist/index.js +2 -2
  7. package/dist/permission-item-Df_aagL1.js +1266 -0
  8. package/dist/{yqg-permission-DfFns5kK.js → yqg-permission-BjVCs5lN.js} +3483 -3538
  9. package/dist/yqg-permission.umd.js +250 -0
  10. package/package.json +13 -3
  11. package/plugins/alioss.ts +237 -0
  12. package/src/App.vue +7 -8
  13. package/src/assets/category.png +0 -0
  14. package/src/axios/index.ts +6 -1
  15. package/src/components/apply-modal.vue +254 -157
  16. package/src/components/category-selector.vue +130 -0
  17. package/src/components/permission-item.vue +230 -0
  18. package/src/components/success-modal.vue +4 -4
  19. package/src/components/yqg-permission.vue +23 -110
  20. package/src/hooks/useAttributesCache.ts +21 -0
  21. package/src/hooks/useCategory.ts +20 -0
  22. package/src/hooks/useDragable.ts +9 -10
  23. package/src/hooks/useFormat.ts +56 -0
  24. package/src/hooks/useStatus.ts +82 -0
  25. package/src/i18n/zh-CH.ts +9 -2
  26. package/src/main.ts +2 -0
  27. package/src/typings/index.d.ts +35 -2
  28. package/src/utils/index.ts +9 -0
  29. package/src/yqg-permission/index.ts +13 -1
  30. package/vite.config.ts +18 -2
  31. package/dist/apply-modal-COwJCSGK.js +0 -8742
  32. package/dist/checkbox-item-DyKSHMQJ.js +0 -4991
  33. package/dist/index-DKDl-l25.js +0 -6164
  34. package/dist/index.umd.cjs +0 -259
  35. package/src/assets/apply.png +0 -0
  36. package/src/components/checkbox-item.vue +0 -201
@@ -0,0 +1,230 @@
1
+ <template>
2
+ <div class="crane-flex-center permission-item-wraper">
3
+ <Tag v-if="item.securityLevel" :bordered="false"
4
+ :style="{ color: levelMap[item.securityLevel].color, background: levelMap[item.securityLevel].background }"
5
+ class="crane-tag-position">
6
+ {{ levelMap[item.securityLevel].text }}
7
+ </Tag>
8
+
9
+ <div style="flex-shrink: 0">{{ t(`operationType.${item.operationType}`) }}|
10
+ </div>
11
+ <Popover>
12
+ <template #content>
13
+ <div style="max-width: 400px;">{{ item.name }}</div>
14
+ </template>
15
+ <div class="crane-text-overflow">{{ item.shortName }}</div>
16
+ </Popover>
17
+ <Tag v-if="item.businessApplyType" :bordered="false"
18
+ class="crane-tag-position crane-margin-left-4 crane-margin-right-0"
19
+ :class="['PENDING'].includes(item.businessApplyType) ? '' : 'crane-disabled-color'">
20
+ {{ statusMap[item.businessApplyType] }}
21
+ {{ item.businessApplyType === 'TEMP_OWNER' ? `(${(item?.ownStatusVO?.dayDiff > 0 ?
22
+ t('lastDays', {
23
+ count:
24
+ item?.ownStatusVO?.dayDiff
25
+ }) : t('today'))})` : ''}}
26
+ </Tag>
27
+
28
+ <Popover v-if="item.desc">
29
+ <template #content>
30
+ <div style="max-width: 400px;">{{ item.desc }}</div>
31
+ </template>
32
+ <QuestionCircleOutlined class="crane-weak-color crane-margin-left-4" />
33
+ </Popover>
34
+
35
+ <Popover v-if="item.relatedCompleteNames?.length">
36
+ <template #content>
37
+ <div style="max-width: 400px;">
38
+ {{ t('adaptDepartment') }}:{{item.relatedCompleteNames.map((item: any) => {
39
+ return item;
40
+ }).join('、') }}
41
+ </div>
42
+ </template>
43
+ <div class="crane-flex-center crane-margin-left-4">
44
+ <img :src="departmentImg" height="14" width="14">
45
+ <span class="crane-weak-color crane-margin-left-4">{{ item.relatedCompleteNames.length
46
+ }}</span>
47
+ </div>
48
+ </Popover>
49
+
50
+ <!-- 数据维度 -->
51
+ <img v-if="item.categoryVOS?.length" :src="categoryImg" height="16" width="16" class="crane-margin-left-4 ">
52
+ <Popover v-if="item.categoryVOS?.length">
53
+ <template #content>
54
+ <div style="max-width: 400px;">
55
+ <div>{{ t('categoryTips') }}</div>
56
+ <div v-for="category in item.categoryVOS" :key="category.id">{{ getCategoryValue(category) }}
57
+ </div>
58
+ </div>
59
+ </template>
60
+ <div class="crane-weak-color crane-margin-left-4 crane-text-overflow">
61
+ {{item.categoryVOS?.map((item:
62
+ any) => {
63
+ return item.categoryName;
64
+ }).join('、')
65
+ }}325kjfhkjdhfkdshfkjdshglkjshdfgkjkjdhfkdshfkjdshglkjshdfgkjkjdhfkdshfkjdshglkjshdfgkjkjdhfkdshfkjdshglkjshdfgkjsfd
66
+ </div>
67
+ </Popover>
68
+
69
+ <!-- 选择框 -->
70
+ <span v-if="checkedKeys.includes(item.feature)" class="crane-weak-color crane-margin-left-12">
71
+ {{ t('availableTime') }}:
72
+ <Select v-model:value="validTime" style="width: 100px"
73
+ :disabled="DISABLED_STATUS.includes(item.businessApplyType)"
74
+ :options="DISABLED_STATUS.includes(item.businessApplyType) ? validTimeOptions : tempTimeOptions"
75
+ @change="onChangeTimeHandler" size="small">
76
+ </Select>
77
+ </span>
78
+
79
+ </div>
80
+ </template>
81
+ <script lang="ts" setup>
82
+ import { PropType, ref, watch, defineEmits, computed } from 'vue';
83
+ import { Tag, Popover, Select } from 'ant-design-vue';
84
+ import { QuestionCircleOutlined } from '@ant-design/icons-vue';
85
+ import departmentImg from '@/assets/department.png';
86
+ import categoryImg from '@/assets/category.png';
87
+ import t from '../utils';
88
+
89
+ const OWNER_STATUS = 'OWNER';
90
+ const PENDING_STATUS = 'PENDING';
91
+ const DISABLED_STATUS = [OWNER_STATUS, PENDING_STATUS];
92
+
93
+ const levelMap:LevelMapType = {
94
+ L1: {
95
+ color: '#1AA83B',
96
+ text: t('levels.L1'),
97
+ background: '#E3F9E9',
98
+ },
99
+ L2: {
100
+ color: '#F37D1C',
101
+ text: t('levels.L2'),
102
+ background: '#FFE4BA'
103
+ },
104
+ L3: {
105
+ color: '#F2494B',
106
+ text: t('levels.L3'),
107
+ background: '#FDCDC5'
108
+ },
109
+ };
110
+
111
+
112
+ let emit = defineEmits(['onChangeTime', 'updateTime']);
113
+
114
+ let props = defineProps({
115
+ checkedKeys: {
116
+ type: Array as PropType<string[]>,
117
+ default: () => []
118
+ },
119
+ validTimeOptions: {
120
+ type: Array as PropType<OptionsType[]>,
121
+ default: () => []
122
+ },
123
+ item: {
124
+ type: Object as PropType<PermissionType>,
125
+ default: () => {}
126
+ }
127
+ });
128
+
129
+ const statusMap = t('status');
130
+ const validTime = ref('');
131
+
132
+ const tempTimeOptions = computed(() => {
133
+ return props.validTimeOptions.filter((item: any) => {
134
+ return item.value !== 'FOREVER';
135
+ });
136
+ });
137
+
138
+
139
+ //1登录人所在部门 = 权限适用范围,都默认90天,不需要区分等级和类型,
140
+ //2登录人所在部门 ≠ 权限适用范围,根据等级来,高(L3)默认给7天,中(L2)默认给30天,低(L1)默认给60天
141
+ const setDefaultTime = (item: PermissionType) => {
142
+ if (OWNER_STATUS.includes(item.businessApplyType)) {
143
+ return item.virtualOwnState?.timeStatus
144
+ }
145
+ if (PENDING_STATUS.includes(item.businessApplyType)) {
146
+ return item.pendingValidTime
147
+ }
148
+ const validMap = {
149
+ L1: 'SIXTY_DAYS',
150
+ L2: 'THIRTY_DAYS',
151
+ L3: 'SEVEN_DAYS',
152
+ };
153
+ const { relatedDepartmentIds = [], curDepartmentId = 0, securityLevel } = item;
154
+ if (relatedDepartmentIds?.includes(curDepartmentId as number)) {
155
+ item.validTime = 'NINETY_DAYS';
156
+ } else {
157
+ item.validTime = validMap[securityLevel];
158
+ }
159
+ return item.validTime;
160
+ };
161
+
162
+ const getCategoryValue = (category: CategoryType) => {
163
+ return `【${category.categoryName}】:${category.attributeValues?.map((item: any) => item.attributeName)?.join('、') || t('empty')}`;
164
+ };
165
+
166
+ watch(() => props.checkedKeys, (newVal, oldVal) => {
167
+ if ((oldVal && !oldVal.includes(props.item.feature)) && newVal.includes(props.item.feature)) {
168
+ validTime.value = setDefaultTime(props.item);
169
+ props.item.validTime = setDefaultTime(props.item);
170
+ emit('updateTime', props.item);
171
+ }}, { immediate: true });
172
+
173
+ const onChangeTimeHandler = (value:any) => {
174
+ props.item.validTime = value;
175
+ emit('updateTime', props.item);
176
+ emit('onChangeTime', props.item);
177
+ };
178
+
179
+
180
+ </script>
181
+ <style scoped>
182
+ .crane-flex-center {
183
+ display: flex;
184
+ align-items: center;
185
+ white-space: nowrap;
186
+ }
187
+
188
+ .permission-item-wraper {
189
+ padding-right: 32px;
190
+ }
191
+ .crane-checkbox-line {
192
+ line-height: 28px;
193
+ display: flex;
194
+ align-items: center;
195
+ }
196
+
197
+ .crane-tag-position {
198
+ margin-right: 4px;
199
+ font-size: 10px;
200
+ padding: 2px 4px;
201
+ line-height: 12px;
202
+ font-weight: 500;
203
+ }
204
+ .crane-margin-right-0 {
205
+ margin-right: 0;
206
+ }
207
+ .crane-margin-left-4 {
208
+ margin-left: 4px;
209
+ }
210
+ .crane-margin-right-4 {
211
+ margin-right: 4px;
212
+ }
213
+ .crane-margin-left-12 {
214
+ margin-left: 12px;
215
+ }
216
+ .crane-disabled-color {
217
+ color: #C9CDD4;
218
+ }
219
+ .crane-weak-color {
220
+ color: #86909C;
221
+ }
222
+ .crane-text-overflow {
223
+ max-width: 160px;
224
+ overflow: hidden;
225
+ text-overflow: ellipsis;
226
+ white-space: nowrap;
227
+ }
228
+
229
+
230
+ </style>
@@ -53,8 +53,8 @@
53
53
  defineExpose({countDown});
54
54
 
55
55
  </script>
56
- <style>
57
- .yqg-permission-modal-wrap .yqg-permission-modal-confirm-btns {
58
- text-align: center!important;
59
- }
56
+ <style scoped>
57
+ :deep(.yqg-permission-modal-wrap .yqg-permission-modal-confirm-btns) {
58
+ text-align: center!important;
59
+ }
60
60
  </style>
@@ -1,41 +1,29 @@
1
1
  <template>
2
- <ConfigProvider
3
- prefixCls="yqg-permission"
4
- :theme="{
2
+ <ConfigProvider prefixCls="yqg-permission" :theme="{
5
3
  token: {
6
4
  colorPrimary: props.color,
7
5
  }
8
- }"
9
- >
6
+ }">
10
7
  <div class="crane-wraper">
11
8
  <template v-if="[COM_TYPE.FLOATBUTTON, COM_TYPE.TEXT].includes(type)">
12
- <FloatButton
13
- ref="dragElement"
14
- type="primary"
15
- :tooltip="t('clickToApply')"
16
- :style="{
9
+ <FloatButton ref="dragElement" type="primary" :tooltip="t('clickToApply')" :style="{
17
10
  right: RIGHT_DEFAULT,
18
11
  top: currentTop,
19
- }"
20
- >
12
+ }">
21
13
  <template #icon>
22
- <img :src="applyIconUrl" height="20" width="20"/>
14
+ <img :src="applyIconUrl" height="20" width="20" />
23
15
  </template>
24
16
  </FloatButton>
25
17
  </template>
26
18
  <template v-else-if="type===COM_TYPE.CUSTOM">
27
19
  <div @click="showModal">
28
- <slot name="custom"/>
20
+ <slot name="custom" />
29
21
  </div>
30
22
  </template>
31
23
  <template v-else>
32
24
  <!-- 可申请 -->
33
25
  <template v-if="curStatus.status === STATUS_MAP.DEFAULT">
34
- <img
35
- :src="curStatus.imageUrl"
36
- height="200"
37
- width="200"
38
- style="margin-top: calc(50vh - 273px)" />
26
+ <img :src="curStatus.imageUrl" height="200" width="200" style="margin-top: calc(50vh - 273px)" />
39
27
  <div class="crane-margin10">
40
28
  {{ t('unavailableTips') }}
41
29
  </div>
@@ -45,31 +33,22 @@
45
33
  </template>
46
34
  <!-- 审批中 -->
47
35
  <template v-if="curStatus.status === STATUS_MAP.PENDING">
48
- <img
49
- :src="curStatus.imageUrl"
50
- height="200"
51
- width="200"
52
- style="margin-top: calc(50vh - 273px)" />
36
+ <img :src="curStatus.imageUrl" height="200" width="200" style="margin-top: calc(50vh - 273px)" />
53
37
  <div class="crane-margin10">
54
- <span
55
- class="crane-unapply"
56
- v-html="t('appliedTips', {
38
+ <span class="crane-unapply" v-html="t('appliedTips', {
57
39
  status: `<style>.crane-unapply span {color: orange;}</style><span>${curStatus.tips}</span>`
58
40
  })">
59
41
  </span>
60
42
  </div>
61
43
  <div>
62
- <Button class="crane-margin-right10" @click="goViewApproval">{{t('viewApprovalDetail')}}</Button>
44
+ <Button class="crane-margin-right10"
45
+ @click="goViewApproval">{{t('viewApprovalDetail')}}</Button>
63
46
  <Button type="primary" @click="showModal">+ {{t('applyMore')}}</Button>
64
47
  </div>
65
48
  </template>
66
49
  <!-- 不可申请 -->
67
50
  <div v-if="curStatus.status === STATUS_MAP.NO" class="crane-wraper">
68
- <img
69
- :src="curStatus.imageUrl"
70
- height="200"
71
- width="200"
72
- style="margin-top: calc(50vh - 273px)" />
51
+ <img :src="curStatus.imageUrl" height="200" width="200" style="margin-top: calc(50vh - 273px)" />
73
52
  <div class="crane-margin10">
74
53
  {{ t('unapplyTips') }}
75
54
  <Popover>
@@ -83,13 +62,8 @@
83
62
  </template>
84
63
  </div>
85
64
 
86
- <ApplyModal
87
- v-model="open"
88
- :permissionList="permissionList"
89
- :workNumber="workNumber"
90
- :businessCode="businessCode"
91
- @onSuccess="() => emit('onSuccess')"
92
- @onSubmit="getPermissions">
65
+ <ApplyModal v-model="open" :permissionList="permissionList" :spining="loading" :workNumber="workNumber"
66
+ :businessCode="businessCode" @onSuccess="() => emit('onSuccess')" @onSubmit="getPermissions">
93
67
  </ApplyModal>
94
68
 
95
69
  </ConfigProvider>
@@ -97,12 +71,13 @@
97
71
  <script lang="ts" setup>
98
72
  import { ref, defineAsyncComponent, computed, watchEffect, watch } from 'vue';
99
73
  import { Button, ConfigProvider, Popover , message, FloatButton} from 'ant-design-vue';
100
- import applyUrl from '@/assets/applying.png';
101
74
  import applyIconUrl from '@/assets/applyicon.png';
102
75
  import noauthority from '@/assets/noauthority.png';
103
76
  import Http from '../axios/index';
104
77
  import t from '../utils';
105
78
  import useDraggable from '../hooks/useDragable';
79
+ import useStatus from '../hooks/useStatus';
80
+ import useFormat from '../hooks/useFormat';
106
81
 
107
82
  const STATUS_MAP = {
108
83
  DEFAULT: 'DEFAULT',
@@ -154,6 +129,7 @@
154
129
 
155
130
  const open = ref(false);
156
131
  const curApproving = ref<PermissionType>();
132
+ const loading = ref(false);
157
133
  let permissionList = ref<PermissionListType>([]);
158
134
  let curStatus = ref<Record<string, any>>({
159
135
  imageUrl: noauthority,
@@ -175,70 +151,6 @@
175
151
  return code.split('.')[0];
176
152
  })
177
153
 
178
- const formatPermissionsData = (data: PermissionListType) => {
179
- const arr:PermissionListType = [];
180
- const flattenData = (list: PermissionListType) => {
181
- list.forEach((item) => {
182
- item.name = item.name.replace(/^[^.]+\./, '');
183
- if (item.children) {
184
- flattenData(item.children);
185
- } else {
186
- arr.push(item);
187
- }
188
- })
189
- };
190
- flattenData(data);
191
-
192
- // 需要排序,规则:businessApplyType 为 null 在前面, PENDING. OWNER 在中间, NO 在后面
193
- // 然后再根据 L1, L2, L3 排序
194
- const sort = [ null, 'TEMP_OWNER', 'PENDING', 'OWNER', 'NO'];
195
- const levelSort = ['L1', 'L2', 'L3'];
196
- const sortMap = new Map(sort.map((value, index) => [value, index]));
197
- const levelSortMap = new Map(levelSort.map((value, index) => [value, index]));
198
-
199
- arr.sort((a, b) => {
200
- return (sortMap.get(a.businessApplyType) ?? 0) - (sortMap.get(b.businessApplyType) ?? 0)
201
- || (levelSortMap.get(a.securityLevel) ?? 0) - (levelSortMap.get(b.securityLevel) ?? 0);
202
- });
203
-
204
- return arr;
205
- }
206
-
207
- const getStatus = (data: PermissionListType) => {
208
- if (!data.length) {
209
- return {
210
- imageUrl: noauthority,
211
- status: ''
212
- };
213
- }
214
-
215
- const current = data.find((per) => per.businessApplyType === STATUS_MAP.PENDING);
216
- const cannotApply = data.every((per) => per.businessApplyType === STATUS_MAP.NO);
217
-
218
- if (current) {
219
- curApproving.value = current;
220
- return {
221
- imageUrl: applyUrl,
222
- status: STATUS_MAP.PENDING,
223
- tips: t('status.PENDING'),
224
- url: current.oaFlowUrl,
225
- };
226
- };
227
-
228
- if (cannotApply) {
229
- return {
230
- imageUrl: noauthority,
231
- status: STATUS_MAP.NO,
232
- tips: data[0].admin?.map((item) => `${item.name}(${item.departmentName})`)?.join('、'),
233
- };
234
- };
235
-
236
- return {
237
- imageUrl: noauthority,
238
- status: STATUS_MAP.DEFAULT,
239
- }
240
- };
241
-
242
154
  const goViewApproval = () => {
243
155
  const url = curApproving.value?.oaFlowUrl;
244
156
  if (!url) return;
@@ -255,11 +167,13 @@
255
167
  workNumber,
256
168
  features: permissions.toString(),
257
169
  };
170
+
171
+ loading.value = true;
258
172
 
259
173
  const res = await Http.getPermissions(params);
260
- permissionList.value = formatPermissionsData(res.body || []);
261
-
262
- curStatus.value = getStatus(permissionList.value);
174
+ permissionList.value = useFormat(res.body || []);
175
+ curStatus.value = useStatus(permissionList.value, curApproving);
176
+ loading.value = false;
263
177
  };
264
178
 
265
179
  const showModal = () => {
@@ -292,5 +206,4 @@
292
206
  margin-right: 10px;
293
207
  }
294
208
  </style>
295
-
296
- ../hooks/useDragable
209
+ ../hooks/useSort../hooks/useFormat
@@ -0,0 +1,21 @@
1
+ import { watch, reactive } from 'vue';
2
+ import Http from '../axios/index';
3
+
4
+ const categoryValuesMap = reactive<Record<number, []>>({});
5
+ export default function useAttributesCache(categoryList: CategoryType[]) {
6
+
7
+ watch(() => categoryList, (newVal) => {
8
+ newVal.forEach(async (item) => {
9
+ if (!categoryValuesMap[item.id]) {
10
+ const res = await Http.getCategoryValues(item.id);
11
+ const { flatAttributeValue, treeAttributeValue, showWay } = res.body;
12
+ categoryValuesMap[item.id] = showWay === 'TREE' ? treeAttributeValue : flatAttributeValue;
13
+ }
14
+ });
15
+
16
+ }, { immediate: true });
17
+
18
+ return {
19
+ categoryValuesMap
20
+ }
21
+ }
@@ -0,0 +1,20 @@
1
+
2
+
3
+ import { deepTree } from '../utils';
4
+ export default function useCategory(tree: PermissionType[], checkedIds: string[]): CategoryType[] {
5
+ const categoryList: CategoryType[] = [];
6
+ deepTree(tree, (item) => {
7
+ if (!item.children && checkedIds.includes(item.feature)) {
8
+ item.categoryVOS.forEach((category: any) => {
9
+ category.attributeValueIds_view = category?.attributeValueIds || [];
10
+ categoryList.push(category);
11
+ });
12
+ }
13
+ });
14
+ // 需要去重
15
+ const map = new Map();
16
+ categoryList.forEach((item) => {
17
+ map.set(item.id, item);
18
+ });
19
+ return Array.from(map.values());
20
+ }
@@ -11,7 +11,6 @@ export default function useDraggable(props: { top: any }, showModal: () => void)
11
11
  const dragElement = ref<any>(null);
12
12
 
13
13
  watch(() => props.top, (newVal) => {
14
- console.log('newVal', newVal);
15
14
  currentTop.value = newVal;
16
15
  }, { immediate: true });
17
16
 
@@ -39,6 +38,9 @@ export default function useDraggable(props: { top: any }, showModal: () => void)
39
38
  const onMouseMove = (e: MouseEvent, el: HTMLElement) => {
40
39
  if (!isDragging.value) return;
41
40
 
41
+ e.preventDefault(); // 阻止默认行为
42
+ e.stopPropagation(); // 阻止事件冒泡
43
+
42
44
  // 移动的时候yqg-permission-tooltip隐藏
43
45
  const tooltip = document.querySelector('.yqg-permission-tooltip') as HTMLElement;
44
46
  if (tooltip) {
@@ -61,29 +63,26 @@ export default function useDraggable(props: { top: any }, showModal: () => void)
61
63
  e.preventDefault(); // 阻止默认行为
62
64
  e.stopPropagation(); // 阻止事件冒泡
63
65
 
66
+ // 卸载拖拽
67
+ isDragging.value = false;
68
+ // 清除事件监听
69
+ document.removeEventListener('mousemove', (e) => onMouseMove(e, el));
70
+ document.removeEventListener('mouseup', (e) => onMouseUp(e, el));
71
+
64
72
  // // 获取元素当前的位置
65
73
  const { x: currentX, y: currentY } = getPosition(el);
66
74
  if ( Math.abs(currentY - initialY.value) < 10 && Math.abs(currentX - initialX.value) < 10) {
67
75
  showModal();
68
- // 卸载拖拽
69
- isDragging.value = false;
70
76
 
71
77
  return;
72
78
  }
73
79
 
74
-
75
- isDragging.value = false;
76
80
  const { clientY } = e;
77
-
78
81
  // 在鼠标松开时设置x为初始位置,y为鼠标当前位置
79
82
  const { x, y } = constrainToScreen(initialX.value, clientY - currentTop.value + initialY.value, el);
80
83
  el.style.transition = 'all 0.3s';
81
84
  el.style.left = `${x}px`;
82
85
  el.style.top = `${y}px`;
83
-
84
- // 清除事件监听
85
- document.removeEventListener('mousemove', (e) => onMouseMove(e, el));
86
- document.removeEventListener('mouseup', (e) => onMouseUp(e, el));
87
86
  };
88
87
 
89
88
  // 鼠标按下时的处理函数
@@ -0,0 +1,56 @@
1
+ const Category = {
2
+ AUTO: 'AUTO',
3
+ MANAL: 'MANAL'
4
+ }
5
+ const StatusType = {
6
+ PENDING: 'PENDING',
7
+ NO: 'NO',
8
+ OWNER: 'OWNER',
9
+ TEMP_OWNER: 'TEMP_OWNER'
10
+ }
11
+ export default function useFormat(tree: PermissionListType) {
12
+ function sortTree(
13
+ tree: PermissionListType,
14
+ sortMap: Map<string | null, number>,
15
+ levelSortMap: Map<string | null, number>
16
+ ) {
17
+ return tree.map((node) => {
18
+ node.key = node.feature;
19
+
20
+ if (!node.children || node.children.length === 0) {
21
+ node.categoryVOS = (node.categoryVOS || []).filter((item: any) => item.configWay !== Category.AUTO);
22
+
23
+ if ([StatusType.NO].includes(node.businessApplyType)) {
24
+ node.disabled = true;
25
+ }
26
+
27
+ if ([StatusType.OWNER, StatusType.PENDING].includes(node.businessApplyType) && !node.categoryVOS.length) {
28
+ node.disabled = true;
29
+ }
30
+ } else {
31
+ // 递归对子节点进行排序
32
+ node.children = sortTree(node.children, sortMap, levelSortMap);
33
+
34
+ // 检查所有子节点是否 `disabled === true`
35
+ if (node.children.every((child) => child.disabled)) {
36
+ node.disabled = true;
37
+ }
38
+ }
39
+
40
+ return node;
41
+ }).sort((a, b) => {
42
+ return (sortMap.get(a.businessApplyType) ?? 0) - (sortMap.get(b.businessApplyType) ?? 0)
43
+ || (levelSortMap.get(a.securityLevel) ?? 0) - (levelSortMap.get(b.securityLevel) ?? 0);
44
+ });
45
+ }
46
+
47
+ // 需要排序,规则:businessApplyType 为 null 在前面, PENDING. OWNER 在中间, NO 在后面
48
+ // 然后再根据 L1, L2, L3 排序
49
+ const sort = [null, StatusType.TEMP_OWNER, StatusType.PENDING, StatusType.OWNER, StatusType.NO];
50
+ const levelSort = [null, "L1", "L2", "L3"];
51
+ const sortMap = new Map(sort.map((value, index) => [value, index]));
52
+ const levelSortMap = new Map(levelSort.map((value, index) => [value, index]));
53
+
54
+ return sortTree(tree, sortMap, levelSortMap);
55
+ }
56
+
@@ -0,0 +1,82 @@
1
+
2
+
3
+ import noauthority from '@/assets/noauthority.png';
4
+ import applyUrl from '@/assets/applying.png';
5
+ import t from '../utils';
6
+ import type { Ref } from 'vue';
7
+
8
+ interface StatusResult {
9
+ imageUrl: string;
10
+ status: string;
11
+ tips?: string;
12
+ url?: string;
13
+ }
14
+
15
+
16
+
17
+ const STATUS_MAP = {
18
+ PENDING: 'PENDING',
19
+ NO: 'NO',
20
+ DEFAULT: 'DEFAULT',
21
+ };
22
+
23
+ export default function useStatus(
24
+ tree: PermissionListType,
25
+ curApproving: Ref<PermissionType | undefined, PermissionType | undefined>
26
+ ): StatusResult {
27
+ if (!tree.length) {
28
+ return {
29
+ imageUrl: noauthority,
30
+ status: '',
31
+ };
32
+ }
33
+
34
+ // 递归获取所有叶子节点
35
+ const getLeafNodes = (nodes: PermissionListType): PermissionListType => {
36
+ let leafNodes: PermissionListType = [];
37
+ nodes.forEach((node) => {
38
+
39
+ if (node.children && node.children.length > 0) {
40
+ leafNodes = leafNodes.concat(getLeafNodes(node.children));
41
+ } else {
42
+ leafNodes.push(node);
43
+ }
44
+ });
45
+ return leafNodes;
46
+ };
47
+
48
+ const leafNodes = getLeafNodes(tree);
49
+
50
+ // 从叶子节点中查找 current
51
+ const current = leafNodes.find((per) => per.businessApplyType === STATUS_MAP.PENDING);
52
+
53
+ // 判断是否所有叶子节点都是 NO
54
+ const cannotApply = leafNodes.every((per) => per.businessApplyType === STATUS_MAP.NO);
55
+
56
+ if (current) {
57
+ curApproving.value = current;
58
+ return {
59
+ imageUrl: applyUrl,
60
+ status: STATUS_MAP.PENDING,
61
+ tips: t('status.PENDING'),
62
+ url: current.oaFlowUrl,
63
+ };
64
+ }
65
+
66
+ if (cannotApply) {
67
+ const adminNames = leafNodes
68
+ .flatMap((node) => node.admin?.map((item) => `${item.name}(${item.departmentName})`))
69
+ .filter(Boolean)
70
+ .join('、');
71
+ return {
72
+ imageUrl: noauthority,
73
+ status: STATUS_MAP.NO,
74
+ tips: adminNames,
75
+ };
76
+ }
77
+
78
+ return {
79
+ imageUrl: noauthority,
80
+ status: STATUS_MAP.DEFAULT,
81
+ };
82
+ };