@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.
- package/README.md +50 -38
- package/dist/apply-modal-CpmDDWWV.js +12865 -0
- package/dist/category-selector-BQ0-kg3o.js +1275 -0
- package/dist/index-D_0ZQip-.js +2972 -0
- package/dist/index-wLkVeDMW.js +5040 -0
- package/dist/index.js +2 -2
- package/dist/permission-item-Df_aagL1.js +1266 -0
- package/dist/{yqg-permission-DfFns5kK.js → yqg-permission-BjVCs5lN.js} +3483 -3538
- package/dist/yqg-permission.umd.js +250 -0
- package/package.json +13 -3
- package/plugins/alioss.ts +237 -0
- package/src/App.vue +7 -8
- package/src/assets/category.png +0 -0
- package/src/axios/index.ts +6 -1
- package/src/components/apply-modal.vue +254 -157
- package/src/components/category-selector.vue +130 -0
- package/src/components/permission-item.vue +230 -0
- package/src/components/success-modal.vue +4 -4
- package/src/components/yqg-permission.vue +23 -110
- package/src/hooks/useAttributesCache.ts +21 -0
- package/src/hooks/useCategory.ts +20 -0
- package/src/hooks/useDragable.ts +9 -10
- package/src/hooks/useFormat.ts +56 -0
- package/src/hooks/useStatus.ts +82 -0
- package/src/i18n/zh-CH.ts +9 -2
- package/src/main.ts +2 -0
- package/src/typings/index.d.ts +35 -2
- package/src/utils/index.ts +9 -0
- package/src/yqg-permission/index.ts +13 -1
- package/vite.config.ts +18 -2
- package/dist/apply-modal-COwJCSGK.js +0 -8742
- package/dist/checkbox-item-DyKSHMQJ.js +0 -4991
- package/dist/index-DKDl-l25.js +0 -6164
- package/dist/index.umd.cjs +0 -259
- package/src/assets/apply.png +0 -0
- 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
|
-
|
|
58
|
-
|
|
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"
|
|
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
|
-
|
|
87
|
-
|
|
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 =
|
|
261
|
-
|
|
262
|
-
|
|
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
|
+
}
|
package/src/hooks/useDragable.ts
CHANGED
|
@@ -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
|
+
};
|