@yqg/permission 1.0.0-beta.0
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/.vscode/extensions.json +3 -0
- package/README.md +5 -0
- package/dist/apply-modal-Ce5S_Tci.js +6821 -0
- package/dist/checkbox-item-CKI49e8K.js +4688 -0
- package/dist/index-Cquyab03.js +6162 -0
- package/dist/index.js +5 -0
- package/dist/index.umd.cjs +271 -0
- package/dist/vite.svg +1 -0
- package/dist/yqg-permission-CnUnm_PT.js +16882 -0
- package/index.html +14 -0
- package/package.json +29 -0
- package/public/vite.svg +1 -0
- package/src/App.vue +79 -0
- package/src/assets/applying.png +0 -0
- package/src/assets/arrow.png +0 -0
- package/src/assets/department.png +0 -0
- package/src/assets/noauthority.png +0 -0
- package/src/axios/axios.ts +59 -0
- package/src/axios/index.ts +15 -0
- package/src/components/apply-modal.vue +177 -0
- package/src/components/approval-steps.vue +67 -0
- package/src/components/checkbox-item.vue +194 -0
- package/src/components/success-modal.vue +51 -0
- package/src/components/yqg-permission.vue +208 -0
- package/src/i18n/en-US.ts +52 -0
- package/src/i18n/index.ts +11 -0
- package/src/i18n/zh-CH.ts +52 -0
- package/src/main.ts +9 -0
- package/src/style.css +81 -0
- package/src/typings/index.d.ts +53 -0
- package/src/utils/index.ts +47 -0
- package/src/vite-env.d.ts +1 -0
- package/src/yqg-permission/index.ts +61 -0
- package/tsconfig.app.json +25 -0
- package/tsconfig.json +10 -0
- package/tsconfig.node.json +23 -0
- package/vite.config.ts +32 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<contextHolder></contextHolder>
|
|
3
|
+
</template>
|
|
4
|
+
<script lang="ts" setup>
|
|
5
|
+
import { createVNode } from 'vue';
|
|
6
|
+
import { CheckCircleFilled } from '@ant-design/icons-vue';
|
|
7
|
+
import { Modal } from 'ant-design-vue';
|
|
8
|
+
import t from '../utils';
|
|
9
|
+
|
|
10
|
+
const [modal, contextHolder] = Modal.useModal();
|
|
11
|
+
|
|
12
|
+
const countDown = (url: string) => {
|
|
13
|
+
let secondsToGo = 10;
|
|
14
|
+
const modal1 = modal.confirm({
|
|
15
|
+
title: t('resoultTitle'),
|
|
16
|
+
content: t('successTips'),
|
|
17
|
+
cancelText: `${t('close')}(${secondsToGo}s)`,
|
|
18
|
+
okText:`${t('viewApprovalDetail')}>>`,
|
|
19
|
+
wrapClassName: 'success-modal-wrap',
|
|
20
|
+
icon: createVNode(CheckCircleFilled, {style: 'color: #52c41a;'}),
|
|
21
|
+
onOk: () => {
|
|
22
|
+
window.open(url);
|
|
23
|
+
location.reload();
|
|
24
|
+
},
|
|
25
|
+
onCancel: () => {
|
|
26
|
+
modal1.destroy();
|
|
27
|
+
location.reload();
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const interval = setInterval(() => {
|
|
32
|
+
secondsToGo -= 1;
|
|
33
|
+
modal1.update({
|
|
34
|
+
cancelText: `${t('close')}(${secondsToGo}s)`,
|
|
35
|
+
});
|
|
36
|
+
}, 1000);
|
|
37
|
+
|
|
38
|
+
setTimeout(() => {
|
|
39
|
+
clearInterval(interval);
|
|
40
|
+
modal1.destroy();
|
|
41
|
+
}, secondsToGo * 1000);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
defineExpose({countDown});
|
|
45
|
+
|
|
46
|
+
</script>
|
|
47
|
+
<style scoped>
|
|
48
|
+
::v-deep .success-modal-wrap .yqg-permission-modal-confirm-btns {
|
|
49
|
+
text-align: center;
|
|
50
|
+
}
|
|
51
|
+
</style>
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<ConfigProvider
|
|
3
|
+
v-if="allPermissions.length"
|
|
4
|
+
prefixCls="yqg-permission"
|
|
5
|
+
:theme="{
|
|
6
|
+
token: {
|
|
7
|
+
colorPrimary: props.color,
|
|
8
|
+
}}">
|
|
9
|
+
<div class="crane-wraper">
|
|
10
|
+
<template v-if="type==='text'">
|
|
11
|
+
<TypographyLink @click="showModal">{{t('permissionApply')}}</TypographyLink>
|
|
12
|
+
</template>
|
|
13
|
+
<template v-else-if="type==='custom'">
|
|
14
|
+
<div @click="showModal">
|
|
15
|
+
<slot name="custom"></slot>
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
18
|
+
<template v-else>
|
|
19
|
+
<img
|
|
20
|
+
:src="curStatus.imageUrl"
|
|
21
|
+
height="200"
|
|
22
|
+
width="200"
|
|
23
|
+
style="margin-top: calc(50vh - 273px)" />
|
|
24
|
+
<!-- 可申请 -->
|
|
25
|
+
<template v-if="curStatus.status === statusMap.DEFAULT">
|
|
26
|
+
<div style="margin: 10px">
|
|
27
|
+
{{ t('unavailableTips') }}
|
|
28
|
+
</div>
|
|
29
|
+
<div>
|
|
30
|
+
<Button type="primary" @click="showModal">+ {{t('applyPermission')}}</Button>
|
|
31
|
+
</div>
|
|
32
|
+
</template>
|
|
33
|
+
<!-- 审批中 -->
|
|
34
|
+
<template v-else-if="curStatus.status === statusMap.PENDING">
|
|
35
|
+
<div style="margin: 10px">
|
|
36
|
+
<span
|
|
37
|
+
class="crane-unapply"
|
|
38
|
+
v-html="t('appliedTips', {
|
|
39
|
+
status: `<style>.crane-unapply span {color: orange;}</style><span>${curStatus.tips}</span>`
|
|
40
|
+
})">
|
|
41
|
+
</span>
|
|
42
|
+
</div>
|
|
43
|
+
<div>
|
|
44
|
+
<Button style="margin-right: 10px;">{{t('viewApprovalDetail')}}</Button>
|
|
45
|
+
<Button type="primary" @click="showModal">+ {{t('applyMore')}}</Button>
|
|
46
|
+
</div>
|
|
47
|
+
</template>
|
|
48
|
+
<!-- 不可申请 -->
|
|
49
|
+
<div v-else style="margin: 10px">
|
|
50
|
+
{{ t('unapplyTips') }}
|
|
51
|
+
<Popover>
|
|
52
|
+
<template #content>
|
|
53
|
+
{{t('manager')}}: {{ curStatus.tips }}
|
|
54
|
+
</template>
|
|
55
|
+
{{ t('callManager') }}
|
|
56
|
+
</Popover>
|
|
57
|
+
</div>
|
|
58
|
+
</template>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<ApplyModal
|
|
62
|
+
v-model="open"
|
|
63
|
+
:permissionList="permissionList"
|
|
64
|
+
:workNumber="workNumber"
|
|
65
|
+
:businessCode="businessCode"
|
|
66
|
+
@onSuccess="getPermissions">
|
|
67
|
+
</ApplyModal>
|
|
68
|
+
|
|
69
|
+
</ConfigProvider>
|
|
70
|
+
</template>
|
|
71
|
+
<script lang="ts" setup>
|
|
72
|
+
import { ref, defineAsyncComponent, computed, watchEffect, watch} from 'vue';
|
|
73
|
+
import {Button, ConfigProvider, TypographyLink, Popover } from 'ant-design-vue';
|
|
74
|
+
import applyUrl from '@/assets/applying.png';
|
|
75
|
+
import noauthority from '@/assets/noauthority.png';
|
|
76
|
+
import Http from '../axios/index';
|
|
77
|
+
import t from '../utils';
|
|
78
|
+
const ApplyModal = defineAsyncComponent(() =>
|
|
79
|
+
import('./apply-modal.vue')
|
|
80
|
+
);
|
|
81
|
+
const statusMap = {
|
|
82
|
+
DEFAULT: 'DEFAULT',
|
|
83
|
+
PENDING: 'PENDING',
|
|
84
|
+
NO: 'NO',
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const props = defineProps({
|
|
88
|
+
workNumber: {
|
|
89
|
+
type: String,
|
|
90
|
+
default: ''
|
|
91
|
+
},
|
|
92
|
+
permissions: {
|
|
93
|
+
type: [String, Array<String>],
|
|
94
|
+
default: []
|
|
95
|
+
},
|
|
96
|
+
businessCode: {
|
|
97
|
+
type: String,
|
|
98
|
+
default: ''
|
|
99
|
+
},
|
|
100
|
+
locale: {
|
|
101
|
+
type: String,
|
|
102
|
+
default: 'zh-CN'
|
|
103
|
+
},
|
|
104
|
+
color: {
|
|
105
|
+
type: String,
|
|
106
|
+
default: '#1677ff'
|
|
107
|
+
},
|
|
108
|
+
type: {
|
|
109
|
+
type: String,
|
|
110
|
+
default: 'default'
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
const emit = defineEmits(['onSuccess']);
|
|
114
|
+
|
|
115
|
+
const open = ref(false);
|
|
116
|
+
let permissionList = ref<PermissionListType>([]);
|
|
117
|
+
let curStatus = ref<Record<string, any>>({
|
|
118
|
+
imageUrl: noauthority,
|
|
119
|
+
status: statusMap.DEFAULT,
|
|
120
|
+
})
|
|
121
|
+
const allPermissions = computed(() => {
|
|
122
|
+
if (Array.isArray(props.permissions)) {
|
|
123
|
+
return props.permissions;
|
|
124
|
+
} else {
|
|
125
|
+
return props.permissions.split(',');
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const formatPermissionsData = (data: PermissionListType) => {
|
|
130
|
+
const arr:PermissionListType = [];
|
|
131
|
+
const flattenData = (list: PermissionListType) => {
|
|
132
|
+
list.forEach((item) => {
|
|
133
|
+
if (item.children) {
|
|
134
|
+
flattenData(item.children);
|
|
135
|
+
} else {
|
|
136
|
+
arr.push(item);
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
};
|
|
140
|
+
flattenData(data);
|
|
141
|
+
// 需要排序,规则:businessApplyType 为 null 在前面, PENDING. OWNER 在中间, NO 在后面
|
|
142
|
+
// 然后再根据 L1, L2, L3 排序
|
|
143
|
+
const sort = [ null, 'PENDING', 'OWNER', 'NO'];
|
|
144
|
+
const levelSort = ['L1', 'L2', 'L3'];
|
|
145
|
+
arr.sort((a, b) => {
|
|
146
|
+
return sort.indexOf(a.businessApplyType) - sort.indexOf(b.businessApplyType) || levelSort.indexOf(a.securityLevel) - levelSort.indexOf(b.securityLevel);
|
|
147
|
+
});
|
|
148
|
+
return arr;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const getStatus = (data: PermissionListType) => {
|
|
152
|
+
if (!data.length) return curStatus.value;
|
|
153
|
+
const current = data.find((per) => per.businessApplyType === statusMap.PENDING);
|
|
154
|
+
const cannotApply = data.every((per) => per.businessApplyType === statusMap.NO);
|
|
155
|
+
if (current) {
|
|
156
|
+
return {
|
|
157
|
+
imageUrl: applyUrl,
|
|
158
|
+
status: statusMap.PENDING,
|
|
159
|
+
tips: t('status.PENDING'),
|
|
160
|
+
url: current.oaFlowUrl,
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
if (cannotApply) {
|
|
165
|
+
return {
|
|
166
|
+
imageUrl: noauthority,
|
|
167
|
+
status: statusMap.NO,
|
|
168
|
+
tips: data[0].admin?.join(','),
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
return curStatus.value;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const getPermissions = async () => {
|
|
175
|
+
if (!allPermissions.value.length || !props.businessCode || !props.workNumber) return;
|
|
176
|
+
|
|
177
|
+
const params = {
|
|
178
|
+
businessCode: props.businessCode,
|
|
179
|
+
features: allPermissions.value.toString(),
|
|
180
|
+
workNumber: props.workNumber,
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
let res = await Http.getPermissions(params);
|
|
184
|
+
permissionList.value = formatPermissionsData(res.body || []);
|
|
185
|
+
curStatus.value = getStatus(permissionList.value);
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const showModal = () => {
|
|
189
|
+
open.value = !open.value;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
watchEffect(getPermissions);
|
|
193
|
+
|
|
194
|
+
watch(() => props.locale, (cur, pre) => {
|
|
195
|
+
if (cur === pre) return;
|
|
196
|
+
localStorage.setItem('permission_locale', props.locale);
|
|
197
|
+
}, {immediate: true})
|
|
198
|
+
|
|
199
|
+
</script>
|
|
200
|
+
<style scoped>
|
|
201
|
+
.crane-wraper {
|
|
202
|
+
display: flex;
|
|
203
|
+
align-items: center;
|
|
204
|
+
flex-direction: column;
|
|
205
|
+
font-size: 14px;
|
|
206
|
+
}
|
|
207
|
+
</style>
|
|
208
|
+
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
permissionApply: '权限申请',
|
|
3
|
+
applyPermission: '申请权限',
|
|
4
|
+
applyReason: '申请理由',
|
|
5
|
+
approvalProcess: '审批流程',
|
|
6
|
+
applyReason1: '新入职员工申请',
|
|
7
|
+
applyReason2: '临时项目',
|
|
8
|
+
applyReason3: '数据查询与分析',
|
|
9
|
+
applyReasonPlaceholder: '请尽可能详细描述申请理由',
|
|
10
|
+
cancel: '取消',
|
|
11
|
+
submit: '确定',
|
|
12
|
+
close: '关闭',
|
|
13
|
+
viewApprovalDetail: '查看审批详情',
|
|
14
|
+
applyMore: '继续申请其他权限',
|
|
15
|
+
successTips: '已提交申请,审批通过后可拥有相关权限',
|
|
16
|
+
resoultTitle: '操作结果反馈',
|
|
17
|
+
start: '发起',
|
|
18
|
+
end: '结束',
|
|
19
|
+
noNeed: '无需审批',
|
|
20
|
+
adaptDepartment: '适用部门',
|
|
21
|
+
noApprovalProcess: '无审批流程',
|
|
22
|
+
excessTips: '一次最多可申请{number}个权限',
|
|
23
|
+
unavailableTips: '您暂无权限查看/操作该页面,请点击按钮进行申请',
|
|
24
|
+
appliedTips: '权限已申请,正在{status}...',
|
|
25
|
+
unapplyTips: '您暂无权限查看/操作该页面,且该页面中没有您可以申请的权限,',
|
|
26
|
+
callManager: '如有需要请联系系统管理员',
|
|
27
|
+
manager: '系统管理员',
|
|
28
|
+
availableTime: '有效期',
|
|
29
|
+
selectPlaceholder: '请选择权限点',
|
|
30
|
+
reasonPlaceholder: '请输入申请理由',
|
|
31
|
+
availiables: {
|
|
32
|
+
SEVEN_DAYS: '7天',
|
|
33
|
+
THIRTY_DAYS: '30天',
|
|
34
|
+
SIXTY_DAYS: '60天',
|
|
35
|
+
NINETY_DAYS: '90天',
|
|
36
|
+
FOREVER: '永久有效',
|
|
37
|
+
},
|
|
38
|
+
levels: {
|
|
39
|
+
L1: '低',
|
|
40
|
+
L2: '中',
|
|
41
|
+
L3: '高',
|
|
42
|
+
},
|
|
43
|
+
status: {
|
|
44
|
+
PENDING: '审批中',
|
|
45
|
+
NO: '不可申请',
|
|
46
|
+
OWNER: '已拥有',
|
|
47
|
+
},
|
|
48
|
+
operationType: {
|
|
49
|
+
QUERY: '查询',
|
|
50
|
+
MANAGE: '操作',
|
|
51
|
+
}
|
|
52
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
permissionApply: '权限申请',
|
|
3
|
+
applyPermission: '申请权限',
|
|
4
|
+
applyReason: '申请理由',
|
|
5
|
+
approvalProcess: '审批流程',
|
|
6
|
+
applyReason1: '新入职员工申请',
|
|
7
|
+
applyReason2: '临时项目',
|
|
8
|
+
applyReason3: '数据查询与分析',
|
|
9
|
+
applyReasonPlaceholder: '请尽可能详细描述申请理由',
|
|
10
|
+
cancel: '取消',
|
|
11
|
+
submit: '确定',
|
|
12
|
+
close: '关闭',
|
|
13
|
+
viewApprovalDetail: '查看审批详情',
|
|
14
|
+
applyMore: '继续申请其他权限',
|
|
15
|
+
successTips: '已提交申请,审批通过后可拥有相关权限',
|
|
16
|
+
resoultTitle: '操作结果反馈',
|
|
17
|
+
start: '发起',
|
|
18
|
+
end: '结束',
|
|
19
|
+
noNeed: '无需审批',
|
|
20
|
+
adaptDepartment: '适用部门',
|
|
21
|
+
noApprovalProcess: '无审批流程',
|
|
22
|
+
excessTips: '一次最多可申请{number}个权限',
|
|
23
|
+
unavailableTips: '您暂无权限查看/操作该页面,请点击按钮进行申请',
|
|
24
|
+
appliedTips: '权限已申请,正在{status}...',
|
|
25
|
+
unapplyTips: '您暂无权限查看/操作该页面,且该页面中没有您可以申请的权限,',
|
|
26
|
+
callManager: '如有需要请联系系统管理员',
|
|
27
|
+
manager: '系统管理员',
|
|
28
|
+
availableTime: '有效期',
|
|
29
|
+
selectPlaceholder: '请选择权限点',
|
|
30
|
+
reasonPlaceholder: '请输入申请理由',
|
|
31
|
+
availiables: {
|
|
32
|
+
SEVEN_DAYS: '7天',
|
|
33
|
+
THIRTY_DAYS: '30天',
|
|
34
|
+
SIXTY_DAYS: '60天',
|
|
35
|
+
NINETY_DAYS: '90天',
|
|
36
|
+
FOREVER: '永久有效',
|
|
37
|
+
},
|
|
38
|
+
levels: {
|
|
39
|
+
L1: '低',
|
|
40
|
+
L2: '中',
|
|
41
|
+
L3: '高',
|
|
42
|
+
},
|
|
43
|
+
status: {
|
|
44
|
+
PENDING: '审批中',
|
|
45
|
+
NO: '不可申请',
|
|
46
|
+
OWNER: '已拥有',
|
|
47
|
+
},
|
|
48
|
+
operationType: {
|
|
49
|
+
QUERY: '查询',
|
|
50
|
+
MANAGE: '操作',
|
|
51
|
+
}
|
|
52
|
+
};
|
package/src/main.ts
ADDED
package/src/style.css
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
3
|
+
line-height: 1.5;
|
|
4
|
+
font-weight: 400;
|
|
5
|
+
color-scheme: light dark;
|
|
6
|
+
color: rgba(255, 255, 255, 87%);
|
|
7
|
+
background-color: #242424;
|
|
8
|
+
font-synthesis: none;
|
|
9
|
+
text-rendering: optimizelegibility;
|
|
10
|
+
-webkit-font-smoothing: antialiased;
|
|
11
|
+
-moz-osx-font-smoothing: grayscale;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
a {
|
|
15
|
+
font-weight: 500;
|
|
16
|
+
color: #646cff;
|
|
17
|
+
text-decoration: inherit;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
a:hover {
|
|
21
|
+
color: #535bf2;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
body {
|
|
25
|
+
margin: 0;
|
|
26
|
+
display: flex;
|
|
27
|
+
place-items: center;
|
|
28
|
+
min-width: 320px;
|
|
29
|
+
min-height: 100vh;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
h1 {
|
|
33
|
+
font-size: 3.2em;
|
|
34
|
+
line-height: 1.1;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
button {
|
|
38
|
+
border-radius: 8px;
|
|
39
|
+
border: 1px solid transparent;
|
|
40
|
+
padding: 0.6em 1.2em;
|
|
41
|
+
font-size: 1em;
|
|
42
|
+
font-weight: 500;
|
|
43
|
+
font-family: inherit;
|
|
44
|
+
background-color: #1a1a1a;
|
|
45
|
+
cursor: pointer;
|
|
46
|
+
transition: border-color 0.25s;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
button:hover {
|
|
50
|
+
border-color: #646cff;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
button:focus,
|
|
54
|
+
button:focus-visible {
|
|
55
|
+
outline: 4px auto -webkit-focus-ring-color;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.card {
|
|
59
|
+
padding: 2em;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
#app {
|
|
63
|
+
max-width: 1280px;
|
|
64
|
+
margin: 0 auto;
|
|
65
|
+
padding: 2rem;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@media (prefers-color-scheme: light) {
|
|
69
|
+
:root {
|
|
70
|
+
color: #213547;
|
|
71
|
+
background-color: #fff;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
a:hover {
|
|
75
|
+
color: #747bff;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
button {
|
|
79
|
+
background-color: #f9f9f9;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
declare enum LevelType {
|
|
2
|
+
L1 = 'L1',
|
|
3
|
+
L2 = 'L2',
|
|
4
|
+
L3 = 'L3'
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
declare enum StatusType {
|
|
8
|
+
PENDING = 'PENDING',
|
|
9
|
+
OWNER = 'OWNER',
|
|
10
|
+
NO = 'NO'
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
declare type PermissionType = {
|
|
14
|
+
name: string;
|
|
15
|
+
roleId: number;
|
|
16
|
+
desc: string;
|
|
17
|
+
businessCode: string;
|
|
18
|
+
feature: string;
|
|
19
|
+
validTime?: string;
|
|
20
|
+
operationType: string;
|
|
21
|
+
securityLevel: LevelType;
|
|
22
|
+
relatedDepartments?: any[];
|
|
23
|
+
relatedDepartmentIds?: number[];
|
|
24
|
+
curDepartmentId?: number;
|
|
25
|
+
businessApplyType: StatusType;
|
|
26
|
+
oaFlowUrl?: string;
|
|
27
|
+
children?: PermissionListType;
|
|
28
|
+
admin?: any[];
|
|
29
|
+
};
|
|
30
|
+
declare type PermissionListType = PermissionType[];
|
|
31
|
+
|
|
32
|
+
declare type LevelMapType = {
|
|
33
|
+
[key in LevelType]: {
|
|
34
|
+
color: string;
|
|
35
|
+
text: string;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
declare type StatusMapType = {
|
|
40
|
+
[key in StatusType]: {
|
|
41
|
+
color: string;
|
|
42
|
+
text: string;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
declare type formStateType = {
|
|
47
|
+
applyBusinessCode: string,
|
|
48
|
+
roleIds: number[],
|
|
49
|
+
roleVoList: any[],
|
|
50
|
+
applyReason: string,
|
|
51
|
+
submitWorkNumber: string,
|
|
52
|
+
|
|
53
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import language from '../i18n';
|
|
2
|
+
|
|
3
|
+
type optionsType = {
|
|
4
|
+
[key: string]: any;
|
|
5
|
+
};
|
|
6
|
+
const t = (key: string, options?: optionsType) => {
|
|
7
|
+
// key的格式为:'xxx.xxx.xxx'
|
|
8
|
+
const en = localStorage.getItem('permission_locale') || 'en-US';
|
|
9
|
+
const keys = key.split('.');
|
|
10
|
+
let result = language[en as string] || language['en-US'];
|
|
11
|
+
for (let i = 0; i < keys.length; i++) {
|
|
12
|
+
result = result[keys[i]];
|
|
13
|
+
}
|
|
14
|
+
// 替换参数
|
|
15
|
+
if (options) {
|
|
16
|
+
Object.keys(options).forEach((k) => {
|
|
17
|
+
result = result.replace(new RegExp(`{${k}}`, 'g'), options[k]);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return result || key;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const throttle = (fn: Function, delay: number) => {
|
|
24
|
+
let timer: any = null;
|
|
25
|
+
return function () {
|
|
26
|
+
if (timer) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
timer = setTimeout(() => {
|
|
30
|
+
fn(arguments);
|
|
31
|
+
timer = null;
|
|
32
|
+
}, delay*1000);
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const formatOptions = (enumkey:string) => {
|
|
37
|
+
const enumMap = t(enumkey);
|
|
38
|
+
return Object.keys(enumMap).map((key) => {
|
|
39
|
+
return {
|
|
40
|
+
label: enumMap[key],
|
|
41
|
+
value: key
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
})
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default t;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { defineAsyncComponent, defineCustomElement } from 'vue';
|
|
2
|
+
const YqgPermissionApply = defineAsyncComponent(() => import('../components/yqg-permission.vue'));
|
|
3
|
+
|
|
4
|
+
const defineElement = (tagName: string): void => {
|
|
5
|
+
customElements.define(
|
|
6
|
+
tagName,
|
|
7
|
+
defineCustomElement(YqgPermissionApply, {
|
|
8
|
+
shadowRoot: false,
|
|
9
|
+
styles: [],
|
|
10
|
+
}),
|
|
11
|
+
);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
interface Options {
|
|
15
|
+
tagName?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface YqgPermissionType {
|
|
19
|
+
tagName: string;
|
|
20
|
+
hasInit: boolean;
|
|
21
|
+
start: (options: Options) => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class YqgPermission implements YqgPermissionType {
|
|
25
|
+
tagName: string;
|
|
26
|
+
hasInit: boolean;
|
|
27
|
+
|
|
28
|
+
constructor() {
|
|
29
|
+
this.tagName = 'yqg-permission';
|
|
30
|
+
this.hasInit = false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
start(options?: Options): void {
|
|
34
|
+
if (!window || !window.customElements) {
|
|
35
|
+
console.error('yqg-permission is not supported in this environment');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (this.hasInit) {
|
|
39
|
+
console.warn('yqg-permission has already been initialized');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
this.hasInit = true;
|
|
44
|
+
if (options?.tagName) {
|
|
45
|
+
if (/^yqg-permission(-\S+)?/.test(options.tagName)) {
|
|
46
|
+
this.tagName = options.tagName;
|
|
47
|
+
} else {
|
|
48
|
+
console.error(`${options.tagName} is invalid tagName`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (window.customElements.get(this.tagName)) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
defineElement(this.tagName);
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export default new YqgPermission();
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"typeRoots": ["node_modules/@types", "src/types"],
|
|
9
|
+
|
|
10
|
+
/* Bundler mode */
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"allowImportingTsExtensions": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"moduleDetection": "force",
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
|
|
17
|
+
/* Linting */
|
|
18
|
+
"strict": true,
|
|
19
|
+
"noUnusedLocals": true,
|
|
20
|
+
"noUnusedParameters": true,
|
|
21
|
+
"noFallthroughCasesInSwitch": true
|
|
22
|
+
},
|
|
23
|
+
"composite": true,
|
|
24
|
+
"include": ["src"]
|
|
25
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["ES2023"],
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
|
|
8
|
+
/* Bundler mode */
|
|
9
|
+
"moduleResolution": "bundler",
|
|
10
|
+
"allowImportingTsExtensions": true,
|
|
11
|
+
"isolatedModules": true,
|
|
12
|
+
"moduleDetection": "force",
|
|
13
|
+
"noEmit": true,
|
|
14
|
+
|
|
15
|
+
/* Linting */
|
|
16
|
+
"strict": true,
|
|
17
|
+
"noUnusedLocals": true,
|
|
18
|
+
"noUnusedParameters": true,
|
|
19
|
+
"noFallthroughCasesInSwitch": true
|
|
20
|
+
},
|
|
21
|
+
"composite": true,
|
|
22
|
+
"include": ["vite.config.ts"]
|
|
23
|
+
}
|