af-mobile-client-vue3 1.0.54

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 (156) hide show
  1. package/.editorconfig +38 -0
  2. package/.env +7 -0
  3. package/.env.development +4 -0
  4. package/.env.envoiceShow +7 -0
  5. package/.env.production +7 -0
  6. package/.husky/commit-msg +1 -0
  7. package/.husky/pre-commit +1 -0
  8. package/.vscode/extensions.json +7 -0
  9. package/.vscode/settings.json +61 -0
  10. package/LICENSE +21 -0
  11. package/README.md +181 -0
  12. package/af-example-mobile-vue-web.iml +9 -0
  13. package/build/vite/index.ts +91 -0
  14. package/build/vite/vconsole.ts +44 -0
  15. package/eslint.config.js +7 -0
  16. package/index.html +17 -0
  17. package/mock/data.ts +20 -0
  18. package/mock/index.ts +5 -0
  19. package/mock/modules/prose.mock.ts +16 -0
  20. package/mock/modules/user.mock.ts +152 -0
  21. package/netlify.toml +12 -0
  22. package/package.json +107 -0
  23. package/public/favicon-dark.svg +4 -0
  24. package/public/favicon.ico +0 -0
  25. package/public/favicon.svg +4 -0
  26. package/public/pwa-192x192.png +0 -0
  27. package/public/pwa-512x512.png +0 -0
  28. package/public/safari-pinned-tab.svg +32 -0
  29. package/scripts/verifyCommit.js +19 -0
  30. package/src/App.vue +43 -0
  31. package/src/api/mock/index.ts +30 -0
  32. package/src/api/user/index.ts +40 -0
  33. package/src/assets/common/default-user-profile.png +0 -0
  34. package/src/assets/img/apps/apply-web.png +0 -0
  35. package/src/assets/img/apps/example-web.png +0 -0
  36. package/src/assets/img/apps/iot-web.png +0 -0
  37. package/src/assets/img/apps/linepatrol-web.png +0 -0
  38. package/src/assets/img/apps/monitor-web.png +0 -0
  39. package/src/assets/img/apps/oa-web.png +0 -0
  40. package/src/assets/img/apps/revenue-web.png +0 -0
  41. package/src/assets/img/apps/safe-check-web.png +0 -0
  42. package/src/assets/img/component/logo.png +0 -0
  43. package/src/assets/img/home/banner1.png +0 -0
  44. package/src/assets/img/home/banner2.png +0 -0
  45. package/src/assets/img/home/banner3.png +0 -0
  46. package/src/assets/img/home/banner4.png +0 -0
  47. package/src/assets/img/home/notice/icon.png +0 -0
  48. package/src/assets/img/user/login/background-shadow-1.svg +20 -0
  49. package/src/assets/img/user/login/logo-background.svg +20 -0
  50. package/src/assets/img/user/login/logo.png +0 -0
  51. package/src/assets/img/user/my/exit-login.png +0 -0
  52. package/src/assets/img/user/my/setting-arrow.png +0 -0
  53. package/src/assets/img/user/my/setting.png +0 -0
  54. package/src/bootstrap.ts +32 -0
  55. package/src/components/core/App/MicroAppView.vue +59 -0
  56. package/src/components/core/BeautifulLoading/index.vue +47 -0
  57. package/src/components/core/NavBar/index.vue +12 -0
  58. package/src/components/core/SvgIcon/index.vue +61 -0
  59. package/src/components/core/Tabbar/index.vue +38 -0
  60. package/src/components/core/Uploader/index.vue +104 -0
  61. package/src/components/core/XMultiSelect/index.vue +196 -0
  62. package/src/components/core/XSelect/index.vue +130 -0
  63. package/src/components/data/XBadge/index.vue +85 -0
  64. package/src/components/data/XCellDetail/index.vue +106 -0
  65. package/src/components/data/XCellList/index.vue +358 -0
  66. package/src/components/data/XCellListFilter/index.vue +392 -0
  67. package/src/components/data/XForm/index.vue +127 -0
  68. package/src/components/data/XFormItem/index.vue +472 -0
  69. package/src/components/data/XReportForm/XReportFormJsonRender.vue +220 -0
  70. package/src/components/data/XReportForm/index.vue +1058 -0
  71. package/src/components/layout/NormalDataLayout/index.vue +70 -0
  72. package/src/components/layout/TabBarLayout/index.vue +40 -0
  73. package/src/components.d.ts +53 -0
  74. package/src/enums/requestEnum.ts +25 -0
  75. package/src/env.d.ts +16 -0
  76. package/src/font-style/PingFangSC-Regular.woff2 +0 -0
  77. package/src/font-style/font.css +4 -0
  78. package/src/hooks/useCommon.ts +9 -0
  79. package/src/hooks/useLogin.ts +97 -0
  80. package/src/icons/svg/bird.svg +1 -0
  81. package/src/icons/svg/check-in.svg +33 -0
  82. package/src/icons/svg/dark.svg +5 -0
  83. package/src/icons/svg/github.svg +5 -0
  84. package/src/icons/svg/light.svg +5 -0
  85. package/src/icons/svg/link.svg +5 -0
  86. package/src/icons/svg/loadError.svg +1 -0
  87. package/src/icons/svg/notFound.svg +1 -0
  88. package/src/icons/svgo.yml +22 -0
  89. package/src/layout/PageLayout.vue +51 -0
  90. package/src/layout/SingleLayout.vue +35 -0
  91. package/src/locales/en-US.json +25 -0
  92. package/src/locales/zh-CN.json +25 -0
  93. package/src/main.ts +48 -0
  94. package/src/plugins/AppData.ts +38 -0
  95. package/src/plugins/GetLoginInfoService.ts +10 -0
  96. package/src/plugins/index.ts +11 -0
  97. package/src/router/README.md +8 -0
  98. package/src/router/guards.ts +60 -0
  99. package/src/router/index.ts +60 -0
  100. package/src/router/invoiceRoutes.ts +33 -0
  101. package/src/router/routes.ts +84 -0
  102. package/src/services/api/Login.ts +6 -0
  103. package/src/services/api/common.ts +98 -0
  104. package/src/services/api/index.ts +7 -0
  105. package/src/services/api/manage.ts +8 -0
  106. package/src/services/restTools.ts +37 -0
  107. package/src/settings.ts +1 -0
  108. package/src/stores/index.ts +7 -0
  109. package/src/stores/modules/cachedView.ts +31 -0
  110. package/src/stores/modules/counter.ts +19 -0
  111. package/src/stores/modules/routeTransitionName.ts +26 -0
  112. package/src/stores/modules/setting.ts +28 -0
  113. package/src/stores/modules/user.ts +180 -0
  114. package/src/stores/mutation-type.ts +7 -0
  115. package/src/styles/app.less +67 -0
  116. package/src/styles/login.less +81 -0
  117. package/src/typing.ts +3 -0
  118. package/src/utils/Storage.ts +124 -0
  119. package/src/utils/authority-utils.ts +87 -0
  120. package/src/utils/common.ts +41 -0
  121. package/src/utils/crypto.ts +39 -0
  122. package/src/utils/dataUtil.ts +42 -0
  123. package/src/utils/dictUtil.ts +51 -0
  124. package/src/utils/http/index.ts +158 -0
  125. package/src/utils/i18n.ts +41 -0
  126. package/src/utils/indexedDB.ts +180 -0
  127. package/src/utils/local-storage.ts +9 -0
  128. package/src/utils/mobileUtil.ts +26 -0
  129. package/src/utils/progress.ts +19 -0
  130. package/src/utils/routerUtil.ts +271 -0
  131. package/src/utils/set-page-title.ts +7 -0
  132. package/src/utils/validate.ts +6 -0
  133. package/src/views/chat/index.vue +153 -0
  134. package/src/views/common/LoadError.vue +64 -0
  135. package/src/views/common/NotFound.vue +68 -0
  136. package/src/views/component/EvaluateRecordView/index.vue +40 -0
  137. package/src/views/component/XCellDetailView/index.vue +216 -0
  138. package/src/views/component/XCellListView/index.vue +36 -0
  139. package/src/views/component/XFormView/index.vue +478 -0
  140. package/src/views/component/XReportFormIframeView/index.vue +45 -0
  141. package/src/views/component/XReportFormView/index.vue +295 -0
  142. package/src/views/component/index.vue +111 -0
  143. package/src/views/component/menu.vue +117 -0
  144. package/src/views/component/notice.vue +46 -0
  145. package/src/views/component/topNav.vue +36 -0
  146. package/src/views/invoiceShow/index.vue +62 -0
  147. package/src/views/user/login/ForgetPasswordForm.vue +93 -0
  148. package/src/views/user/login/LoginForm.vue +145 -0
  149. package/src/views/user/login/LoginTitle.vue +68 -0
  150. package/src/views/user/login/LoginWave.vue +109 -0
  151. package/src/views/user/login/index.vue +22 -0
  152. package/src/views/user/my/index.vue +230 -0
  153. package/src/vue-router.d.ts +9 -0
  154. package/tsconfig.json +43 -0
  155. package/uno.config.ts +32 -0
  156. package/vite.config.ts +110 -0
@@ -0,0 +1,180 @@
1
+ import { defineStore } from 'pinia'
2
+ import { ref } from 'vue'
3
+ import type { RouteRecordRaw } from 'vue-router'
4
+ import { createStorage } from '@af-mobile-client-vue3/utils/Storage'
5
+ import {
6
+ ACCESS_TOKEN,
7
+ APP_LOGIN_KEY,
8
+ APP_PERMISSIONS_KEY,
9
+ APP_ROLES_KEY,
10
+ APP_ROUTES_KEY,
11
+ CURRENT_USER,
12
+ } from '@af-mobile-client-vue3/stores/mutation-type'
13
+ import { OALogin, doLogout, login } from '@af-mobile-client-vue3/api/user'
14
+ import crypto from '@af-mobile-client-vue3/utils/crypto'
15
+ import router from '@af-mobile-client-vue3/router/index'
16
+
17
+ const Storage = createStorage({ storage: localStorage })
18
+
19
+ export interface UserInfo {
20
+ id: number
21
+ username: string
22
+ password: string
23
+ name: string
24
+ avatar: string
25
+ functions: Array<any>
26
+ }
27
+
28
+ interface IUserState {
29
+ token?: string
30
+ userInfo: UserInfo
31
+ lastUpdateTime: number
32
+ permissions: [{ id: string, operation: string[] }]
33
+ roles: [{ id: string, operation: string[] }]
34
+ routesConfig: Array<any>
35
+ single: Array<ExtraRouteRecordRaw>
36
+ login: any
37
+ }
38
+
39
+ type ExtraRouteRecordRaw = RouteRecordRaw & {
40
+ delete: boolean
41
+ fullPath: string
42
+ }
43
+
44
+ interface LoginParams {
45
+ username: string
46
+ password: string
47
+ resourceName: string
48
+ }
49
+
50
+ export const useUserStore = defineStore('app-user', () => {
51
+ const userState = ref<IUserState>({
52
+ userInfo: null,
53
+ token: undefined,
54
+ lastUpdateTime: 0,
55
+ // 旧营收产品$login对象
56
+ login: undefined,
57
+ permissions: null,
58
+ roles: null,
59
+ routesConfig: null,
60
+ single: [],
61
+ } as IUserState)
62
+ const getUserInfo = () => {
63
+ return userState.value.userInfo || Storage.get(CURRENT_USER, {}) || {}
64
+ }
65
+ const getLogin = () => {
66
+ return userState.value.login || Storage.get(APP_LOGIN_KEY, []) || {}
67
+ }
68
+ const getPermissions = () => {
69
+ return userState.value.permissions || Storage.get(APP_PERMISSIONS_KEY, []) || []
70
+ }
71
+ const getRoles = () => {
72
+ return userState.value.roles || Storage.get(APP_ROLES_KEY, []) || []
73
+ }
74
+ const getRoutesConfig = () => {
75
+ return userState.value.routesConfig || Storage.get(APP_ROUTES_KEY, []) || []
76
+ }
77
+ const getToken = () => {
78
+ return userState.value.token || Storage.get(ACCESS_TOKEN, '') as string
79
+ }
80
+ const getLastUpdateTime = () => {
81
+ return userState.value.lastUpdateTime
82
+ }
83
+ const setToken = (token: string | undefined) => {
84
+ Storage.set(ACCESS_TOKEN, token)
85
+ }
86
+ const setUserInfo = (info: UserInfo | null) => {
87
+ userState.value.userInfo = info
88
+ userState.value.lastUpdateTime = new Date().getTime()
89
+ Storage.set(CURRENT_USER, info)
90
+ }
91
+ const setLogin = (login) => {
92
+ userState.value.login = login
93
+ Storage.set(APP_LOGIN_KEY, login)
94
+ }
95
+ const setSingle = (page: ExtraRouteRecordRaw) => {
96
+ if (page.path && page.delete) {
97
+ // 删除
98
+ userState.value.single = userState.value.single.filter(item => item.fullPath !== page.path)
99
+ }
100
+ else if (userState.value.single.filter(item => item.meta.singlePage === page.meta.singlePage).length === 0) {
101
+ // 添加
102
+ userState.value.single.push(page)
103
+ }
104
+ }
105
+ const setPermissions = (permissions: [{ id: string, operation: string[] }]) => {
106
+ userState.value.permissions = permissions
107
+ Storage.set(APP_PERMISSIONS_KEY, permissions)
108
+ }
109
+ const setRoles = (roles: [{ id: string, operation: string[] }]) => {
110
+ userState.value.roles = roles
111
+ Storage.set(APP_PERMISSIONS_KEY, roles)
112
+ }
113
+ const setRoutesConfig = (routesConfig: Array<any>) => {
114
+ userState.value.routesConfig = routesConfig
115
+ Storage.set(APP_ROUTES_KEY, routesConfig)
116
+ }
117
+ const Login = async (params: LoginParams) => {
118
+ try {
119
+ let data: any
120
+ const compatible = import.meta.env.VITE_APP_COMPATIBLE
121
+ if (compatible === 'OA') {
122
+ data = await OALogin(params)
123
+ // save token
124
+ setToken(params.password)
125
+ }
126
+ else {
127
+ data = await login(params)
128
+ // save token
129
+ setToken(data.access_token)
130
+ // 第三方教培系统鉴权兼容
131
+ const LoginTicket = crypto.AESEncrypt(JSON.stringify(params), '3KMKqvgwR8ULbR8Z')
132
+ Storage.set('LoginTicket', LoginTicket)
133
+ }
134
+ return Promise.resolve(data)
135
+ }
136
+ catch (error) {
137
+ return Promise.reject(error)
138
+ }
139
+ }
140
+ const logout = async () => {
141
+ if (getToken) {
142
+ try {
143
+ await doLogout()
144
+ }
145
+ catch {
146
+ console.error('注销Token失败')
147
+ }
148
+ }
149
+ setToken(undefined)
150
+ setUserInfo(null)
151
+ Storage.remove(ACCESS_TOKEN)
152
+ Storage.remove(CURRENT_USER)
153
+ Storage.remove(APP_LOGIN_KEY)
154
+ Storage.remove(APP_PERMISSIONS_KEY)
155
+ Storage.remove(APP_ROLES_KEY)
156
+ Storage.remove(APP_ROUTES_KEY)
157
+ Storage.remove('LoginTicket')
158
+ router.push('/login')
159
+ }
160
+
161
+ return {
162
+ Login,
163
+ getToken,
164
+ getLastUpdateTime,
165
+ logout,
166
+ setUserInfo,
167
+ getUserInfo,
168
+ getLogin,
169
+ getPermissions,
170
+ getRoles,
171
+ getRoutesConfig,
172
+ setLogin,
173
+ setSingle,
174
+ setPermissions,
175
+ setRoles,
176
+ setRoutesConfig,
177
+ }
178
+ })
179
+
180
+ export default useUserStore
@@ -0,0 +1,7 @@
1
+ export const CURRENT_USER = 'CURRENT-USER'
2
+ export const ACCESS_TOKEN = 'Authorization'
3
+ export const APP_LOGIN_KEY = 'admin.login'
4
+ export const APP_PERMISSIONS_KEY = 'admin.permissions'
5
+ export const APP_ROLES_KEY = 'admin.roles'
6
+ export const APP_ROUTES_KEY = 'admin.routes'
7
+ export const APP_WEB_CONFIG_KEY = 'admin.webconfig'
@@ -0,0 +1,67 @@
1
+ :root {
2
+ --base-interval-0: 7px;
3
+ --base-interval-1: 14px;
4
+ --base-interval-2: 28px;
5
+ }
6
+
7
+ #system-app {
8
+ min-height: 100vh;
9
+ position: relative;
10
+ overflow-x: hidden;
11
+ }
12
+
13
+ html {
14
+ background: var(--van-white);
15
+ color-scheme: light;
16
+ }
17
+
18
+ *,
19
+ *::before,
20
+ *::after {
21
+ box-sizing: border-box;
22
+ }
23
+
24
+ .slide-fadein-left-enter-active,
25
+ .slide-fadein-left-leave-active,
26
+ .slide-fadein-right-enter-active,
27
+ .slide-fadein-right-leave-active {
28
+ position: absolute;
29
+ top: 0;
30
+ left: 0;
31
+ transition: opacity 0.3s, transform 0.4s, -webkit-transform 0.4s;
32
+ }
33
+
34
+ .slide-fadein-left-enter-from,
35
+ .slide-fadein-right-leave-to {
36
+ transform: translateX(20px);
37
+ opacity: 0;
38
+ }
39
+
40
+ .slide-fadein-left-leave-to,
41
+ .slide-fadein-right-enter-from {
42
+ transform: translateX(-20px);
43
+ opacity: 0;
44
+ }
45
+
46
+ .slide-left-enter-active,
47
+ .slide-left-leave-active,
48
+ .slide-right-enter-active,
49
+ .slide-right-leave-active {
50
+ will-change: transform;
51
+ transition: transform .3s;
52
+ height: 100%;
53
+ width: 100%;
54
+ top: 0;
55
+ position: absolute;
56
+ backface-visibility: hidden;
57
+ }
58
+
59
+ .slide-right-enter-from,
60
+ .slide-left-leave-to {
61
+ transform: translateX(100%);
62
+ }
63
+
64
+ .slide-right-leave-to,
65
+ .slide-left-enter-from {
66
+ transform: translateX(-100%);
67
+ }
@@ -0,0 +1,81 @@
1
+ .form {
2
+ width: 100%;
3
+ padding: 0 40px;
4
+ .form_field {
5
+ padding-right: 0;
6
+ padding-left: 0;
7
+ :deep(.van-field__label) {
8
+ opacity: 0.7;
9
+ color: rgb(88, 88, 88);
10
+ font-size: 16px;
11
+ font-weight: 400;
12
+ line-height: 23px;
13
+ text-transform: uppercase;
14
+ text-indent: 10px;
15
+ }
16
+ :deep(.van-field__body) {
17
+ height: 40px;
18
+ border-radius: 5px;
19
+ background: rgb(251, 251, 251);
20
+ box-shadow: inset 0 0 1px 0 rgba(0, 0, 0, 0.1);
21
+ color: rgb(71, 71, 71);
22
+ font-size: 16px;
23
+ font-weight: 400;
24
+ padding: 8px 10px;
25
+ opacity: 0.6;
26
+ }
27
+ }
28
+ .extra_setting {
29
+ font-size: 12px;
30
+ font-weight: 400;
31
+ line-height: 12px;
32
+ .extra_setting_for_remember_password {
33
+ opacity: 0.7;
34
+ color: rgb(88, 88, 88);
35
+ span {
36
+ position: relative;
37
+ bottom: 3px;
38
+ left: 5px;
39
+ }
40
+ }
41
+ .extra_setting_for_reset_password {
42
+ position: relative;
43
+ top: 2px;
44
+ opacity: 0.7;
45
+ color: rgb(56, 149, 250);
46
+ }
47
+ }
48
+ .btn {
49
+ height: 50px;
50
+ :deep(.van-button__text) {
51
+ color: rgb(255, 255, 255);
52
+ font-size: 16px;
53
+ font-weight: 700;
54
+ line-height: 23px;
55
+ }
56
+ }
57
+ .login_btn {
58
+ background: rgb(56, 149, 250);
59
+ margin-top: 104px;
60
+ }
61
+ .reset_btn {
62
+ margin: 24px 0;
63
+ }
64
+ .back_btn {
65
+ :deep(.van-button__text) {
66
+ color: rgb(56, 149, 250);
67
+ }
68
+ }
69
+ :deep(.van-cell) {
70
+ background: #ffffff;
71
+ }
72
+ :deep(.van-cell:after) {
73
+ border-bottom: none;
74
+ }
75
+ }
76
+ .login_form {
77
+ margin-top: 65px;
78
+ }
79
+ .forget_password_form {
80
+ margin-top: 15px;
81
+ }
package/src/typing.ts ADDED
@@ -0,0 +1,3 @@
1
+ import type { Ref } from 'vue'
2
+
3
+ export type MaybeRef<T> = T | Ref<T>
@@ -0,0 +1,124 @@
1
+ // 默认缓存期限为7天
2
+ const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7
3
+
4
+ /**
5
+ * 创建本地缓存对象
6
+ */
7
+ export function createStorage({ prefixKey = '', storage = localStorage } = {}) {
8
+ /**
9
+ * 本地缓存类
10
+ * @class Storage
11
+ */
12
+ const Storage = class {
13
+ private storage = storage
14
+ private prefixKey?: string = prefixKey
15
+
16
+ private getKey(key: string) {
17
+ return `${this.prefixKey}${key}`.toUpperCase()
18
+ }
19
+
20
+ /**
21
+ * @description 设置缓存
22
+ * @param {string} key 缓存键
23
+ * @param {*} value 缓存值
24
+ * @param expire
25
+ */
26
+ set(key: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) {
27
+ const stringData = JSON.stringify({
28
+ value,
29
+ expire: expire !== null ? new Date().getTime() + expire * 1000 : null,
30
+ })
31
+ this.storage.setItem(this.getKey(key), stringData)
32
+ }
33
+
34
+ /**
35
+ * 读取缓存
36
+ * @param {string} key 缓存键
37
+ * @param {*=} def 默认值
38
+ */
39
+ get(key: string, def: any = null) {
40
+ const item = this.storage.getItem(this.getKey(key))
41
+ if (item) {
42
+ try {
43
+ const data = JSON.parse(item)
44
+ const { value, expire } = data
45
+ // 在有效期内直接返回
46
+ if (expire === null || expire >= Date.now())
47
+ return value
48
+
49
+ this.remove(key)
50
+ }
51
+ catch (e) {
52
+ return def
53
+ }
54
+ }
55
+ return def
56
+ }
57
+
58
+ /**
59
+ * 从缓存删除某项
60
+ * @param {string} key
61
+ */
62
+ remove(key: string) {
63
+ this.storage.removeItem(this.getKey(key))
64
+ }
65
+
66
+ /**
67
+ * 清空所有缓存
68
+ * @memberOf Cache
69
+ */
70
+ clear(): void {
71
+ this.storage.clear()
72
+ }
73
+
74
+ /**
75
+ * 设置cookie
76
+ * @param {string} name cookie 名称
77
+ * @param {*} value cookie 值
78
+ * @param {number=} expire 过期时间
79
+ * 如果过期时间为设置,默认关闭浏览器自动删除
80
+ * @example
81
+ */
82
+ setCookie(name: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) {
83
+ document.cookie = `${this.getKey(name)}=${value}; Max-Age=${expire}`
84
+ }
85
+
86
+ /**
87
+ * 根据名字获取cookie值
88
+ * @param name
89
+ */
90
+ getCookie(name: string): string {
91
+ const cookieArr = document.cookie.split('; ')
92
+ for (let i = 0, length = cookieArr.length; i < length; i++) {
93
+ const kv = cookieArr[i].split('=')
94
+ if (kv[0] === this.getKey(name))
95
+ return kv[1]
96
+ }
97
+ return ''
98
+ }
99
+
100
+ /**
101
+ * 根据名字删除指定的cookie
102
+ * @param {string} key
103
+ */
104
+ removeCookie(key: string) {
105
+ this.setCookie(key, 1, -1)
106
+ }
107
+
108
+ /**
109
+ * 清空cookie,使所有cookie失效
110
+ */
111
+ clearCookie(): void {
112
+ const keys = document.cookie.match(/[^ =;]+(?==)/g)
113
+ if (keys) {
114
+ for (let i = keys.length; i--;)
115
+ document.cookie = `${keys[i]}=0;expire=${new Date(0).toUTCString()}`
116
+ }
117
+ }
118
+ }
119
+ return new Storage()
120
+ }
121
+
122
+ export const storage = createStorage()
123
+
124
+ export default Storage
@@ -0,0 +1,87 @@
1
+ /**
2
+ * 判断是否有路由的权限
3
+ * @param authority 路由权限配置
4
+ * @param permissions 用户权限集合
5
+ * @returns {boolean|*}
6
+ */
7
+ function hasPermission(authority: any, permissions) {
8
+ let required: string = '*'
9
+ if (typeof authority === 'string')
10
+ required = authority
11
+ else if (Array.isArray(authority))
12
+ required = authority.toString()
13
+ else if (typeof authority === 'object')
14
+ required = authority.permission
15
+
16
+ return required === '*' || hasAnyItem(required, permissions, (r, t) => !!(r === t || r === t.id))
17
+ }
18
+
19
+ /**
20
+ * 判断是否有路由需要的角色
21
+ * @param authority 路由权限配置
22
+ * @param roles 用户角色集合
23
+ */
24
+ function hasRole(authority, roles) {
25
+ let required
26
+ if (typeof authority === 'object')
27
+ required = authority.role
28
+
29
+ return authority === '*' || hasAnyItem(required, roles, (r, t) => !!(r === t || r === t.id))
30
+ }
31
+
32
+ /**
33
+ * 判断目标数组是否有所需元素
34
+ * @param {string | string[]}required 所需元素,数组或单个元素
35
+ * @param {string[] | object[]} source 目标数组
36
+ * @param {Function} filter 匹配条件
37
+ * (r: String, s: String|Object) => boolean
38
+ * @returns {boolean}
39
+ */
40
+ function hasAnyItem(required, source, filter) {
41
+ if (!required)
42
+ return false
43
+
44
+ const checkedList = Array.isArray(required) ? required : [required]
45
+ return !!source.find(s => checkedList.find(r => filter(r, s)))
46
+ }
47
+
48
+ /**
49
+ * 路由权限校验
50
+ * @param route 路由
51
+ * @param permissions 用户权限集合
52
+ * @param roles 用户角色集合
53
+ * @returns {boolean}
54
+ */
55
+ function hasAuthority(route, permissions, roles) {
56
+ // TODO 此处判断可能有问题
57
+ if (!route.meta.pAuthorities)
58
+ return true
59
+
60
+ const authorities = [...route.meta.pAuthorities, route.meta.authority]
61
+ for (const authority of authorities) {
62
+ if (!hasPermission(authority, permissions) && !hasRole(authority, roles))
63
+ return false
64
+ }
65
+ return true
66
+ }
67
+
68
+ /**
69
+ * 根据权限配置过滤菜单数据
70
+ * @param menuData
71
+ * @param permissions
72
+ * @param roles
73
+ */
74
+ function filterMenu(menuData, permissions, roles) {
75
+ return menuData.filter((menu) => {
76
+ if (menu.meta && menu.meta.invisible === undefined) {
77
+ if (!hasAuthority(menu, permissions, roles))
78
+ return false
79
+ }
80
+ if (menu.children && menu.children.length > 0)
81
+ menu.children = filterMenu(menu.children, permissions, roles)
82
+
83
+ return true
84
+ })
85
+ }
86
+
87
+ export { filterMenu, hasAuthority }
@@ -0,0 +1,41 @@
1
+ import useUserStore from '@af-mobile-client-vue3/stores/modules/user'
2
+
3
+ export function hexToRgba(hex: string, opacity: number) {
4
+ const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i
5
+ hex = hex.replace(shorthandRegex, (r, g, b) => {
6
+ return r + r + g + g + b + b
7
+ })
8
+
9
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
10
+ opacity = opacity >= 0 && opacity <= 1 ? Number(opacity) : 1
11
+ return result
12
+ ? `rgba(${
13
+ [Number.parseInt(result[1], 16), Number.parseInt(result[2], 16), Number.parseInt(result[3], 16), opacity].join(
14
+ ',',
15
+ )
16
+ })`
17
+ : hex
18
+ }
19
+
20
+ // 引入本地图片
21
+ export function getImageUrl(url, prefix?): string {
22
+ return new URL(prefix ? prefix + url : url, import.meta.url).href
23
+ }
24
+
25
+ // 获取路由属性
26
+ export function getFunction(link?: string): { children?: any[], link?: string, name?: string, parentId?: string, sort?: number } {
27
+ const FunctionPage = useUserStore().getUserInfo()?.functions?.filter((item) => {
28
+ return item.link === import.meta.env.VITE_APP_PUBLIC_PATH.replace('/', '')
29
+ })
30
+ if (FunctionPage?.length > 0) {
31
+ if (link) {
32
+ if (FunctionPage[0].children?.length > 0) {
33
+ return FunctionPage[0].children?.filter((_item) => {
34
+ return _item.link === link
35
+ })[0]
36
+ }
37
+ }
38
+ return Object.assign({ children: [] }, FunctionPage[0])
39
+ }
40
+ return { children: [] }
41
+ }
@@ -0,0 +1,39 @@
1
+ import AesEncryptJS from 'crypto-js'
2
+ export default {
3
+ /**
4
+ * AES加密
5
+ *
6
+ * @param word
7
+ * @returns {any}
8
+ */
9
+ AESEncrypt(word: string, encryKey: string): string {
10
+ const key = AesEncryptJS.enc.Utf8.parse(encryKey)
11
+ const srcs = AesEncryptJS.enc.Utf8.parse(word)
12
+ const encrypted = AesEncryptJS.AES.encrypt(srcs, key, {
13
+ mode: AesEncryptJS.mode.ECB,
14
+ padding: AesEncryptJS.pad.Pkcs7,
15
+ })
16
+ return encrypted.toString()
17
+ },
18
+ /**
19
+ * AES解密
20
+ *
21
+ * @param word
22
+ * @param encryKey
23
+ * @returns {any}
24
+ */
25
+ AESDecrypt(word: string, encryKey: string): any {
26
+ const key = AesEncryptJS.enc.Utf8.parse(encryKey)
27
+ const decrypt = AesEncryptJS.AES.decrypt(word, key, {
28
+ mode: AesEncryptJS.mode.ECB,
29
+ padding: AesEncryptJS.pad.Pkcs7,
30
+ })
31
+ const ret = AesEncryptJS.enc.Utf8.stringify(decrypt).toString()
32
+ try {
33
+ return JSON.parse(ret)
34
+ }
35
+ catch (e) {
36
+ return ret
37
+ }
38
+ },
39
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * 构造树型结构数据
3
+ * [label,value,children]
4
+ */
5
+ export function handleTree(data: any, id?: string, parentId?: string, children?: string) {
6
+ const config = {
7
+ id: id || 'id',
8
+ parentId: parentId || 'parent_id',
9
+ childrenList: children || 'children',
10
+ }
11
+ const childrenListMap = {}
12
+ const nodeIds = {}
13
+ const tree = []
14
+ for (const d of data) {
15
+ const parentId = d[config.parentId]
16
+ if (childrenListMap[parentId] == null)
17
+ childrenListMap[parentId] = []
18
+
19
+ nodeIds[d[config.id]] = d
20
+ childrenListMap[parentId].push(d)
21
+ }
22
+ for (const d of data) {
23
+ const parentId = d[config.parentId]
24
+ if (nodeIds[parentId] == null)
25
+ tree.push(d)
26
+ }
27
+ for (const t of tree)
28
+ adaptToChildrenList(t)
29
+
30
+ function adaptToChildrenList(o) {
31
+ o.label = o.name
32
+ o.value = o.name
33
+ if (childrenListMap[o[config.id]] !== null)
34
+ o[config.childrenList] = childrenListMap[o[config.id]]
35
+
36
+ if (o[config.childrenList]) {
37
+ for (const c of o[config.childrenList])
38
+ adaptToChildrenList(c)
39
+ }
40
+ }
41
+ return tree
42
+ }