@deppon/create-deppon-app 2.2.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/LICENSE +1 -0
- package/README.md +63 -0
- package/deppon.js +640 -0
- package/package.json +51 -0
- package/template/.env +12 -0
- package/template/.env.dev-local.example +64 -0
- package/template/.env.development.example +64 -0
- package/template/.env.example +1 -0
- package/template/.env.production.example +64 -0
- package/template/.env.test.example +64 -0
- package/template/.eslintignore +2 -0
- package/template/.eslintrc.cjs +14 -0
- package/template/.prettierrc.js +3 -0
- package/template/.vscode/settings.json +8 -0
- package/template/Dockerfile +5 -0
- package/template/README.md +149 -0
- package/template/commitlint.config.js +11 -0
- package/template/gitignore +8 -0
- package/template/index.html +18 -0
- package/template/nginx.conf +70 -0
- package/template/npmrc +2 -0
- package/template/package.json +49 -0
- package/template/preview-server.js +117 -0
- package/template/public/favicon.ico +0 -0
- package/template/public/logo.png +0 -0
- package/template/src/App.vue +123 -0
- package/template/src/api/index.ts +13 -0
- package/template/src/api/prefercenter.ts +23 -0
- package/template/src/api/product.ts +16 -0
- package/template/src/api/user.ts +41 -0
- package/template/src/components/ExpandableMessage.vue +340 -0
- package/template/src/components/PageLayout.vue +43 -0
- package/template/src/config/dictionaryConfig.ts +24 -0
- package/template/src/directives/permission.ts +162 -0
- package/template/src/layouts/BaseLayout.vue +687 -0
- package/template/src/main.ts +27 -0
- package/template/src/router/index.ts +179 -0
- package/template/src/router/route.ts +61 -0
- package/template/src/stores/menu.ts +334 -0
- package/template/src/stores/product.ts +155 -0
- package/template/src/stores/route.ts +79 -0
- package/template/src/stores/user.ts +145 -0
- package/template/src/styles/index.ts +29 -0
- package/template/src/types/dictionary.d.ts +24 -0
- package/template/src/types/vite-env.d.ts +119 -0
- package/template/src/utils/dictionary.ts +188 -0
- package/template/src/utils/errorAnalyzer.ts +217 -0
- package/template/src/utils/messageVNode.ts +15 -0
- package/template/src/utils/request.ts +293 -0
- package/template/src/views/error/401.vue +30 -0
- package/template/src/views/error/403.vue +30 -0
- package/template/src/views/error/404.vue +30 -0
- package/template/src/views/home/index.vue +25 -0
- package/template/tsconfig.json +27 -0
- package/template/vite.config.ts +243 -0
- package/template/yarnrc +3 -0
- package/template/yarnrc.yml +7 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="page-layout">
|
|
3
|
+
<el-scrollbar class="page-layout-scrollbar">
|
|
4
|
+
<slot />
|
|
5
|
+
</el-scrollbar>
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script setup lang="ts">
|
|
10
|
+
import { ElScrollbar } from '@deppon/deppon-ui';
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<style scoped lang="less">
|
|
14
|
+
.page-layout {
|
|
15
|
+
width: 100%;
|
|
16
|
+
height: 100%;
|
|
17
|
+
padding: 15px 0 0 15px;
|
|
18
|
+
box-sizing: border-box;
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
|
|
21
|
+
.page-layout-scrollbar {
|
|
22
|
+
width: 100%;
|
|
23
|
+
height: 100%;
|
|
24
|
+
box-sizing: border-box;
|
|
25
|
+
position: relative;
|
|
26
|
+
z-index: 1;
|
|
27
|
+
overflow-x: hidden;
|
|
28
|
+
|
|
29
|
+
:deep(.el-scrollbar__wrap) {
|
|
30
|
+
overflow-x: hidden;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
:deep(.el-scrollbar__view) {
|
|
34
|
+
height: 100%;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
:deep(.el-scrollbar__bar) {
|
|
38
|
+
z-index: 10;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
</style>
|
|
43
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 前端字典配置文件
|
|
3
|
+
* 在这里配置所有的字典数据
|
|
4
|
+
*/
|
|
5
|
+
import type { DictionaryItem } from '@/types/dictionary';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 字典配置数据
|
|
9
|
+
* key: 字典类型标识
|
|
10
|
+
* value: 字典项数组
|
|
11
|
+
*/
|
|
12
|
+
export const dictionaryConfig: Record<string, DictionaryItem[]> = {
|
|
13
|
+
// 示例:状态字典
|
|
14
|
+
statusOptions: [
|
|
15
|
+
{ code: '1', label: '启用', sort: 1 },
|
|
16
|
+
{ code: '0', label: '禁用', sort: 2 },
|
|
17
|
+
],
|
|
18
|
+
|
|
19
|
+
// 示例:类型字典
|
|
20
|
+
typeOptions: [
|
|
21
|
+
{ code: 'TYPE_A', label: '类型A', sort: 1 },
|
|
22
|
+
{ code: 'TYPE_B', label: '类型B', sort: 2 },
|
|
23
|
+
],
|
|
24
|
+
};
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { Directive, type DirectiveBinding } from 'vue';
|
|
2
|
+
import { getButtonAuth } from '@/api/prefercenter';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 权限指令缓存,避免重复请求
|
|
6
|
+
* key: 权限代码,value: 是否有权限
|
|
7
|
+
*/
|
|
8
|
+
const permissionCache = new Map<string, boolean>();
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 正在请求的权限 Promise Map,用于去重并发请求
|
|
12
|
+
* key: 权限代码,value: Promise<boolean>
|
|
13
|
+
*/
|
|
14
|
+
const pendingRequests = new Map<string, Promise<boolean>>();
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 权限指令
|
|
18
|
+
* 用法: v-permission="/cmc-prefer-web/pricing/request/queryAddWeb"
|
|
19
|
+
* 或者: v-permission="{ code: '/cmc-prefer-web/pricing/request/queryAddWeb' }"
|
|
20
|
+
*
|
|
21
|
+
* 如果用户有权限,元素显示;否则隐藏
|
|
22
|
+
*/
|
|
23
|
+
export const vPermission: Directive = {
|
|
24
|
+
async mounted(el: HTMLElement, binding: DirectiveBinding) {
|
|
25
|
+
await checkPermission(el, binding);
|
|
26
|
+
},
|
|
27
|
+
async updated(el: HTMLElement, binding: DirectiveBinding) {
|
|
28
|
+
// 如果权限代码没有变化,不需要重新检查
|
|
29
|
+
const oldValue = (el as any).__permissionCode;
|
|
30
|
+
const newValue = getPermissionCode(binding);
|
|
31
|
+
if (oldValue === newValue) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
(el as any).__permissionCode = newValue;
|
|
35
|
+
await checkPermission(el, binding);
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 从 binding 中提取权限代码
|
|
41
|
+
*/
|
|
42
|
+
function getPermissionCode(binding: DirectiveBinding): string | null {
|
|
43
|
+
if (typeof binding.value === 'string') {
|
|
44
|
+
return binding.value;
|
|
45
|
+
} else if (binding.value && typeof binding.value === 'object' && binding.value.code) {
|
|
46
|
+
return binding.value.code;
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 请求权限(带去重机制)
|
|
53
|
+
*/
|
|
54
|
+
async function requestPermission(permissionCode: string): Promise<boolean> {
|
|
55
|
+
// 如果正在请求中,等待该请求完成
|
|
56
|
+
if (pendingRequests.has(permissionCode)) {
|
|
57
|
+
return await pendingRequests.get(permissionCode)!;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 创建新的请求 Promise
|
|
61
|
+
const requestPromise = (async () => {
|
|
62
|
+
try {
|
|
63
|
+
const params = [{ code: permissionCode }];
|
|
64
|
+
const response = await getButtonAuth(params);
|
|
65
|
+
|
|
66
|
+
// 判断是否有权限
|
|
67
|
+
// 返回数据格式: [{ isAuth: true, code: "/cmc-prefer-web/pricing/request/queryAddWeb" }]
|
|
68
|
+
// response 直接就是数组,没有 success 和 data 字段
|
|
69
|
+
let hasPermission = false;
|
|
70
|
+
|
|
71
|
+
// 获取返回的数据数组
|
|
72
|
+
let permissionData: any[] = [];
|
|
73
|
+
|
|
74
|
+
if (Array.isArray(response)) {
|
|
75
|
+
// response 本身就是数组(主要情况)
|
|
76
|
+
permissionData = response;
|
|
77
|
+
} else if (response && response.data && Array.isArray(response.data)) {
|
|
78
|
+
// 兼容有 data 字段的情况
|
|
79
|
+
permissionData = response.data;
|
|
80
|
+
} else if (response && response.success !== false && response.data && Array.isArray(response.data)) {
|
|
81
|
+
// 兼容有 success 和 data 字段的情况
|
|
82
|
+
permissionData = response.data;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// 从数组中查找对应权限代码的项
|
|
86
|
+
if (permissionData.length > 0) {
|
|
87
|
+
const permissionItem = permissionData.find((item: any) => item.code === permissionCode);
|
|
88
|
+
if (permissionItem) {
|
|
89
|
+
hasPermission = permissionItem.isAuth === true;
|
|
90
|
+
}
|
|
91
|
+
} else if (response && typeof response === 'object' && !Array.isArray(response) && response.isAuth !== undefined) {
|
|
92
|
+
// 兼容单个对象的情况
|
|
93
|
+
hasPermission = response.isAuth === true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 缓存权限结果
|
|
97
|
+
permissionCache.set(permissionCode, hasPermission);
|
|
98
|
+
|
|
99
|
+
return hasPermission;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error('权限检查失败:', error);
|
|
102
|
+
// 出错时默认返回 false,保证安全性
|
|
103
|
+
permissionCache.set(permissionCode, false);
|
|
104
|
+
return false;
|
|
105
|
+
} finally {
|
|
106
|
+
// 请求完成后,从 pendingRequests 中移除
|
|
107
|
+
pendingRequests.delete(permissionCode);
|
|
108
|
+
}
|
|
109
|
+
})();
|
|
110
|
+
|
|
111
|
+
// 将请求 Promise 存入 Map
|
|
112
|
+
pendingRequests.set(permissionCode, requestPromise);
|
|
113
|
+
|
|
114
|
+
return await requestPromise;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* 检查权限并控制元素显示/隐藏
|
|
119
|
+
*/
|
|
120
|
+
async function checkPermission(el: HTMLElement, binding: DirectiveBinding) {
|
|
121
|
+
try {
|
|
122
|
+
// 获取权限代码
|
|
123
|
+
const permissionCode = getPermissionCode(binding);
|
|
124
|
+
|
|
125
|
+
if (!permissionCode) {
|
|
126
|
+
// 无效值,默认隐藏
|
|
127
|
+
el.style.display = 'none';
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 检查缓存
|
|
132
|
+
if (permissionCache.has(permissionCode)) {
|
|
133
|
+
const hasPermission = permissionCache.get(permissionCode)!;
|
|
134
|
+
el.style.display = hasPermission ? '' : 'none';
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// 请求权限(带去重机制)
|
|
139
|
+
const hasPermission = await requestPermission(permissionCode);
|
|
140
|
+
|
|
141
|
+
// 控制元素显示/隐藏
|
|
142
|
+
el.style.display = hasPermission ? '' : 'none';
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error('权限检查失败:', error);
|
|
145
|
+
// 出错时默认隐藏,保证安全性
|
|
146
|
+
el.style.display = 'none';
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* 清除权限缓存(可选,用于权限变更时刷新)
|
|
152
|
+
*/
|
|
153
|
+
export const clearPermissionCache = () => {
|
|
154
|
+
permissionCache.clear();
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* 清除指定权限的缓存
|
|
159
|
+
*/
|
|
160
|
+
export const clearPermissionCacheByCode = (code: string) => {
|
|
161
|
+
permissionCache.delete(code);
|
|
162
|
+
};
|