yuang-framework-ui-common 1.0.14 → 1.0.15

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.
@@ -0,0 +1,79 @@
1
+ import axios from "axios"
2
+
3
+
4
+ import {showErrorMessage} from '../utils/messageUtils';
5
+ import {alertMessageBox} from '../utils/messageBoxUtils';
6
+
7
+ import {getSsoLoginUrl, clearSsoAccessToken} from '../utils/ssoUtils';
8
+
9
+ const messageMap = {
10
+ requestError: '请求异常',
11
+ responseSturctError: '响应结构错误',
12
+ }
13
+
14
+ const http = axios.create({
15
+ baseURL: (window as any).$config?.apiBaseUrl ?? '/gateway-api',
16
+ timeout: 5000,
17
+ headers: {}
18
+ })
19
+
20
+
21
+ /* 请求拦截 */
22
+ http.interceptors.request.use(config => {
23
+ config.headers["X-Requested-With"] = 'XMLHttpRequest';
24
+
25
+ let gatewayAccessToken = localStorage.getItem("gatewayAccessToken") ?? '';
26
+ let gatewayPublicKey = localStorage.getItem("gatewayPublicKey") ?? '';
27
+ let ssoAccessToken = localStorage.getItem("ssoAccessToken") ?? '';
28
+ if (gatewayAccessToken) {
29
+ config.headers["Gateway-Access-Token"] = gatewayAccessToken;
30
+ }
31
+ if (gatewayPublicKey) {
32
+ config.headers["Gateway-Public-Key"] = gatewayPublicKey;
33
+ }
34
+
35
+ if (ssoAccessToken) {
36
+ config.headers["Sso-Access-Token"] = ssoAccessToken;
37
+ }
38
+ config.headers["Request-Id"] = 'test';
39
+ return config;
40
+ }, error => {
41
+ showErrorMessage(error?.message || messageMap.requestError);
42
+ return Promise.reject(error);
43
+ }
44
+ );
45
+
46
+
47
+ /* 响应拦截器 */
48
+ http.interceptors.response.use((res) => {
49
+ if(!res?.data?.statusCode){
50
+ showErrorMessage(messageMap.responseSturctError);
51
+ return Promise.reject(new Error(messageMap.responseSturctError));
52
+ }
53
+ if (res?.data?.statusCode !== 200) {
54
+ // 登录过期处理
55
+ if (res?.data?.statusCode === 401) {
56
+ alertMessageBox({
57
+ title: '系统提示',
58
+ message: '登录状态已过期, 请退出重新登录!',
59
+ confirmButtonText: '重新登录',
60
+ callback: (action: string) => {
61
+ if (action === 'confirm') {
62
+ clearSsoAccessToken();
63
+ location.href = getSsoLoginUrl();
64
+ }
65
+ }
66
+ });
67
+ return Promise.reject(new Error(res?.data?.message));
68
+ }
69
+ showErrorMessage(res?.data?.message || messageMap.requestError);
70
+ return Promise.reject(new Error(res?.data?.message));
71
+ }
72
+ return res;
73
+ }, (error) => {
74
+ showErrorMessage(error?.message || messageMap.requestError);
75
+ return Promise.reject(error);
76
+ });
77
+
78
+
79
+ export {http}
@@ -0,0 +1,28 @@
1
+ import {isPc} from '../utils/deviceUtils';
2
+
3
+
4
+ import ElementPlus from 'element-plus'
5
+ import 'element-plus/dist/index.css'
6
+ import {ElMessage} from 'element-plus'
7
+
8
+ import vant from 'vant';
9
+ import 'vant/lib/index.css';
10
+
11
+
12
+ import {http} from './httpConfig';
13
+ import moment from 'moment';
14
+
15
+ const initConfig = (app) => {
16
+ app.config.globalProperties.$http = http;
17
+ app.config.globalProperties.$moment = moment;
18
+
19
+ if (isPc()) {
20
+ app.config.globalProperties.$message = ElMessage;
21
+ app.use(ElementPlus);
22
+ } else {
23
+ app.use(vant);
24
+ }
25
+
26
+ }
27
+
28
+ export {initConfig} ;
@@ -1,7 +1,27 @@
1
1
 
2
2
  import CryptoJS from 'crypto-js'
3
3
 
4
- // aes加密
4
+ /**
5
+ * 获取aesKey
6
+ * 生成16位随机码
7
+ * @returns {string}
8
+ */
9
+ const getAesRandomKey = () => {
10
+ var chars = [ '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K', 'L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
11
+ var randomKey = ''
12
+ // 这个地方切记要选择16位,因为美国对密钥长度有限制,选择32位的话加解密会报错,需要根据jdk版本去修改相关jar包,有点恼火,选择16位就不用处理。
13
+ for (var i = 0; i < 16; i++) {
14
+ let id = parseInt((Math.random() * 61).toString());
15
+ randomKey += chars[id]
16
+ }
17
+ return randomKey
18
+ }
19
+
20
+ /**
21
+ * aes加密
22
+ * @param aesKey
23
+ * @param originData
24
+ */
5
25
  const aesEncrypt = (aesKey, originData) => {
6
26
  // 设置一个默认值,如果第二个参数为空采用默认值,不为空则采用新设置的密钥
7
27
  var key = CryptoJS.enc.Utf8.parse(aesKey)
@@ -15,7 +35,11 @@ const aesEncrypt = (aesKey, originData) => {
15
35
  return encrypted.toString()
16
36
  }
17
37
 
18
- // aes解密
38
+ /**
39
+ * aes解密
40
+ * @param aesKey
41
+ * @param originData
42
+ */
19
43
  const aesDecrypt = (aesKey, originData) => {
20
44
  var key = CryptoJS.enc.Utf8.parse(aesKey)
21
45
  var decrypt = CryptoJS.AES.decrypt(originData, key, {
@@ -25,24 +49,9 @@ const aesDecrypt = (aesKey, originData) => {
25
49
  })
26
50
  return CryptoJS.enc.Utf8.stringify(decrypt).toString()
27
51
  }
28
- /**
29
- * 获取aesKey
30
- * 生成16位随机码
31
- * @returns {string}
32
- */
33
- const getAesRandomKey = () => {
34
- var chars = [ '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K', 'L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
35
- var nums = ''
36
- // 这个地方切记要选择16位,因为美国对密钥长度有限制,选择32位的话加解密会报错,需要根据jdk版本去修改相关jar包,有点恼火,选择16位就不用处理。
37
- for (var i = 0; i < 16; i++) {
38
- let id = parseInt((Math.random() * 61).toString());
39
- nums += chars[id]
40
- }
41
- return nums
42
- }
43
52
 
44
53
  export {
54
+ getAesRandomKey,
45
55
  aesEncrypt,
46
- aesDecrypt,
47
- getAesRandomKey
56
+ aesDecrypt
48
57
  }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * 是否移动设备
3
+ */
4
+ const isMd = () => {
5
+ return navigator.userAgent.match(
6
+ /Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile|WPDesktop/i
7
+ );
8
+ }
9
+ /**
10
+ * 是否平板
11
+ */
12
+ const isPad = () => {
13
+ var ua = window.navigator.userAgent
14
+ if (/ipad/i.test(ua)) {
15
+ return true;
16
+ }
17
+ // iPad from IOS13
18
+ var macApp = ua.match(/Macintosh/i) != null
19
+ if (!macApp) {
20
+ return false;
21
+ }
22
+ // need to distinguish between Macbook and iPad
23
+ var canvas = document.createElement('canvas')
24
+ if (!canvas) {
25
+ return false;
26
+ }
27
+ var context = canvas.getContext('webgl') || canvas.getContext('experimental-webgl')
28
+ if (!context) {
29
+ return false;
30
+ }
31
+ var info = (context as any).getExtension('WEBGL_debug_renderer_info')
32
+ if (!info) {
33
+ return false;
34
+ }
35
+ var renderer = (context as any).getParameter(info.UNMASKED_RENDERER_WEBGL)
36
+ if (renderer.indexOf('Apple') != -1) {
37
+ return true;
38
+ }
39
+ return false;
40
+
41
+
42
+ }
43
+ /**
44
+ * 是否个人电脑
45
+ */
46
+ const isPc = () => {
47
+ if (isMd() || isPad()) {
48
+ return false;
49
+ }
50
+ return true;
51
+ }
52
+
53
+ /**
54
+ * 获取设备类型
55
+ * @returns pc/md/unknow
56
+ */
57
+ const getDeviceType = () => {
58
+ if(isPc()){
59
+ return 'pc';
60
+ }
61
+ if(isMd()){
62
+ return 'md';
63
+ }
64
+ return 'unknow';
65
+ }
66
+
67
+ export {
68
+ isMd,
69
+ isPad,
70
+ isPc,
71
+ getDeviceType
72
+ }
@@ -1,14 +1,11 @@
1
1
 
2
- import http from '../config/http';
2
+ import {http} from '../config/httpConfig';
3
3
 
4
4
  const initGateway = () => {
5
5
  return new Promise<void>(async resolve => {
6
6
  let gatewayAccessToken = localStorage.getItem("gatewayAccessToken");
7
7
  if (!gatewayAccessToken) {
8
8
  let res = await http.get('/server/gateway/getGatewayConfig');
9
- if (res.data.statusCode != 200) {
10
- return console.error(res.data.message);
11
- }
12
9
  localStorage.setItem("gatewayAccessToken", res.data.data.gatewayAccessToken);
13
10
  localStorage.setItem("gatewayPublicKey", res.data.data.gatewayPublicKey);
14
11
  }
@@ -0,0 +1,23 @@
1
+ import {isPc} from './deviceUtils';
2
+
3
+ import { ElMessageBox } from 'element-plus/es';
4
+
5
+
6
+
7
+ const alertMessageBox = ({title, message, confirmButtonText, callback}) => {
8
+ if(isPc()) {
9
+ ElMessageBox.close();
10
+ ElMessageBox.alert(message, title, {
11
+ confirmButtonText: confirmButtonText,
12
+ callback: (action) => {
13
+ callback && callback(action);
14
+ },
15
+ type: 'warning',
16
+ draggable: true
17
+ });
18
+ }
19
+ }
20
+
21
+ export {
22
+ alertMessageBox,
23
+ }
@@ -0,0 +1,68 @@
1
+ import {isPc} from './deviceUtils';
2
+
3
+ import {ElMessage} from 'element-plus'
4
+ import {showNotify} from 'vant';
5
+
6
+
7
+ const showSuccessMessage = (message) => {
8
+ showMessage({
9
+ type: 'success',
10
+ message: message,
11
+ });
12
+ }
13
+
14
+ const showWarningMessage = (message) => {
15
+ showMessage({
16
+ type: 'warning',
17
+ message: message,
18
+ });
19
+ }
20
+
21
+ const showInfoMessage = (message) => {
22
+ showMessage({
23
+ type: 'info',
24
+ message: message,
25
+ });
26
+ }
27
+
28
+ const showErrorMessage = (message) => {
29
+ showMessage({
30
+ type: 'error',
31
+ message: message,
32
+ });
33
+ }
34
+
35
+ /**
36
+ * 显示消息
37
+ * @param type 'success' | 'warning' | 'info' | 'error'
38
+ * @param message
39
+ */
40
+ const showMessage = ({type, message}) => {
41
+ if (isPc()) {
42
+ ElMessage({
43
+ type: type,
44
+ message: message,
45
+ duration: 3 * 1000
46
+ })
47
+ } else {
48
+ if (type == 'error') {
49
+ showNotify({type: 'danger', message: message});
50
+ } else if (type == 'info') {
51
+ showNotify({
52
+ message: message,
53
+ color: '#909399',
54
+ background: '#e9e9eb',
55
+ });
56
+ } else {
57
+ showNotify({type: type, message: message});
58
+ }
59
+ }
60
+ }
61
+
62
+ export {
63
+ showSuccessMessage,
64
+ showWarningMessage,
65
+ showInfoMessage,
66
+ showErrorMessage,
67
+ showMessage,
68
+ }
@@ -1,60 +1,66 @@
1
-
2
1
  import JSEncrypt from 'jsencrypt'
3
2
 
4
- // rsa加密
5
- const rsaEncrypt = (Str, afterPublicKey) => {
6
- const encryptor = new JSEncrypt()
7
- encryptor.setPublicKey(afterPublicKey) // 设置公钥
8
- return encryptor.encrypt(Str) // 对数据进行加密
9
- }
10
-
11
- // rsa解密
12
- const rsaDecrypt = (Str, frontPrivateKey) => {
13
- const encryptor = new JSEncrypt()
14
- encryptor.setPrivateKey(frontPrivateKey) // 设置私钥
15
- return encryptor.decrypt(Str) // 对数据进行解密
16
- }
17
3
 
18
- //获取rsa密钥对
4
+ /**
5
+ * 获取rsa密钥对
6
+ */
19
7
  const getRsaKeys = () => {
20
8
  return new Promise((resolve, reject) => {
21
- window.crypto.subtle
22
- .generateKey(
23
- {
24
- name: 'RSA-OAEP',
25
- modulusLength: 2048, //can be 1024, 2048, or 4096
26
- publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
27
- hash: { name: 'SHA-512' } //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
28
- },
29
- true, //whether the key is extractable (i.e. can be used in exportKey)
30
- ['encrypt', 'decrypt'] //must be ["encrypt", "decrypt"] or ["wrapKey", "unwrapKey"]
31
- )
32
- .then(function(key) {
33
- window.crypto.subtle
34
- .exportKey('pkcs8', key.privateKey)
35
- .then(function(keydata1) {
36
- window.crypto.subtle
37
- .exportKey('spki', key.publicKey)
38
- .then(function(keydata2) {
39
- var privateKey = convertText(keydata1, 1)
9
+ window.crypto.subtle.generateKey(
10
+ {
11
+ name: 'RSA-OAEP',
12
+ modulusLength: 2048, //can be 1024, 2048, or 4096
13
+ publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
14
+ hash: {name: 'SHA-512'} //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
15
+ },
16
+ true, //whether the key is extractable (i.e. can be used in exportKey)
17
+ ['encrypt', 'decrypt'] //must be ["encrypt", "decrypt"] or ["wrapKey", "unwrapKey"]
18
+ ).then(function (key) {
19
+ window.crypto.subtle
20
+ .exportKey('pkcs8', key.privateKey)
21
+ .then(function (keydata1) {
22
+ window.crypto.subtle
23
+ .exportKey('spki', key.publicKey)
24
+ .then(function (keydata2) {
25
+ var privateKey = convertText(keydata1, 1)
40
26
 
41
- var publicKey = convertText(keydata2)
27
+ var publicKey = convertText(keydata2)
42
28
 
43
- resolve({ privateKey, publicKey })
44
- })
45
- .catch(function(err) {
46
- reject(err)
47
- })
48
- })
49
- .catch(function(err) {
29
+ resolve({privateKey, publicKey})
30
+ }).catch(function (err) {
50
31
  reject(err)
51
32
  })
52
- })
53
- .catch(function(err) {
33
+ }).catch(function (err) {
54
34
  reject(err)
55
35
  })
36
+ }).catch(function (err) {
37
+ reject(err)
38
+ })
56
39
  })
57
40
  }
41
+
42
+ /**
43
+ * rsa加密
44
+ * @param publicKey
45
+ * @param oiginData
46
+ */
47
+ const rsaEncrypt = (publicKey, oiginData) => {
48
+ const encryptor = new JSEncrypt();
49
+ encryptor.setPublicKey(publicKey);
50
+ return encryptor.encrypt(oiginData);
51
+ }
52
+
53
+ /**
54
+ * rsa解密
55
+ * @param privateKey
56
+ * @param encryptData
57
+ */
58
+ const rsaDecrypt = (privateKey, encryptData) => {
59
+ const encryptor = new JSEncrypt();
60
+ encryptor.setPrivateKey(privateKey);
61
+ return encryptor.decrypt(encryptData);
62
+ }
63
+
58
64
  const convertText = (buffer, isPrivate = 0) => {
59
65
  var binary = ''
60
66
  var bytes = new Uint8Array(buffer)
@@ -70,7 +76,8 @@ const convertText = (buffer, isPrivate = 0) => {
70
76
  }
71
77
 
72
78
  export {
79
+ getRsaKeys,
73
80
  rsaEncrypt,
74
81
  rsaDecrypt,
75
- getRsaKeys
82
+
76
83
  }
@@ -9,7 +9,7 @@ const getSsoLoginUrl = (redirectUrl = '') => {
9
9
  let ssoLoginUrl = ((window as any).$config?.apiFullBaseUrl ?? '') + '/sso-api/server/sso/login';
10
10
  if (!redirectUrl) {
11
11
  ssoLoginUrl += `?redirectUrl=${encodeURIComponent(window.location.href)}`;
12
- } else if (redirectUrl) {
12
+ } else {
13
13
  ssoLoginUrl += `?redirectUrl=${encodeURIComponent(redirectUrl)}`;
14
14
  }
15
15
  return ssoLoginUrl;
@@ -33,18 +33,22 @@ const getSsoLoginRoutePath = (redirectRoutePath = '') => {
33
33
  let ssoLoginRoutePath = '/sso/login';
34
34
  if (!redirectRoutePath) {
35
35
  ssoLoginRoutePath += `?redirectRoutePath=${encodeURIComponent('/sso/login-success')}`;
36
- } else if (redirectRoutePath) {
36
+ } else {
37
37
  ssoLoginRoutePath += `?redirectRoutePath=${encodeURIComponent(redirectRoutePath)}`;
38
38
  }
39
39
  return ssoLoginRoutePath;
40
40
  }
41
41
 
42
+ /**
43
+ * 获取sso加密参数
44
+ * @param password
45
+ */
42
46
  const getSsoEncrypt = (password = '') => {
43
47
  let gatewayPublicKey = localStorage.getItem('gatewayPublicKey');
44
48
  // 每次请求生成aeskey
45
49
  let aesKey = getAesRandomKey();
46
50
  // 用登陆后后端生成并返回给前端的的RSA密钥对的公钥将AES16位密钥进行加密
47
- const rsaAesKey = rsaEncrypt(aesKey, gatewayPublicKey);
51
+ const rsaAesKey = rsaEncrypt(gatewayPublicKey, aesKey);
48
52
  // 使用AES16位的密钥将请求报文加密(使用的是加密前的aes密钥)
49
53
  const encryptPassword = aesEncrypt(aesKey, password);
50
54
 
@@ -0,0 +1,30 @@
1
+ const getExceptionRoutes = () => {
2
+ return [
3
+ {
4
+ path: '/exception/403',
5
+ component: () => import('../../src/views/exception/403/index.vue'),
6
+ meta: {
7
+ title: '403'
8
+ }
9
+ },
10
+ {
11
+ path: '/exception/500',
12
+ component: () => import('../../src/views/exception/500/index.vue'),
13
+ meta: {
14
+ title: '500'
15
+ }
16
+ },
17
+ {
18
+ path: '/:path(.*)*',
19
+ component: () => import('../../src/views/exception/404/index.vue'),
20
+ meta: {
21
+ title: '404'
22
+ }
23
+ }
24
+ ];
25
+
26
+ }
27
+
28
+ export {
29
+ getExceptionRoutes
30
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yuang-framework-ui-common",
3
- "version": "1.0.14",
3
+ "version": "1.0.15",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "scripts": {
@@ -33,6 +33,7 @@
33
33
  "jsencrypt": "^3.3.2",
34
34
  "moment": "^2.30.1",
35
35
  "pinia": "^2.1.7",
36
+ "vant": "^4.9.8",
36
37
  "vue": "^3.4.29",
37
38
  "vue-router": "^4.3.3"
38
39
  },
package/src/App.vue CHANGED
@@ -1,11 +1,20 @@
1
1
  <template>
2
- <RouterView/>
2
+ <RouterView v-if="isShowRouterView"/>
3
3
  </template>
4
4
  <script setup lang="ts">
5
5
  import {RouterView} from 'vue-router'
6
+ import {onBeforeMount, ref, getCurrentInstance} from 'vue';
7
+ import {initGateway} from '../lib/utils/gatewayUtils'
6
8
 
7
- </script>
9
+ let isShowRouterView = ref(false);
10
+
11
+ const {proxy} = getCurrentInstance() as object;
8
12
 
13
+ onBeforeMount(async () => {
14
+ await initGateway();
15
+ isShowRouterView.value = true;
16
+ })
17
+ </script>
9
18
 
10
19
  <style scoped>
11
20
 
package/src/main.ts CHANGED
@@ -4,13 +4,15 @@ import { createPinia } from 'pinia'
4
4
 
5
5
  import App from './App.vue'
6
6
  import router from './router'
7
+ import {initConfig} from '../lib/config/initConfig';
7
8
 
8
9
  const app = createApp(App)
9
10
 
10
11
  app.use(createPinia())
11
12
  app.use(router)
12
13
 
13
- app.use(ElementPlus)
14
+
15
+ initConfig(app);
14
16
 
15
17
  app.mount('#app')
16
18
 
@@ -1,9 +1,27 @@
1
1
  import {createRouter, createWebHistory} from 'vue-router'
2
+ import {getExceptionRoutes} from '../../lib/utils/vueRouterUtils'
2
3
 
3
4
  const router = createRouter({
4
5
  history: createWebHistory(import.meta.env.BASE_URL),
5
6
  routes: [
7
+ {
8
+ path: '/utils/aes-utils',
9
+ component: () => import('@/views/utils/aes-utils.vue')
10
+ },
11
+ {
12
+ path: '/utils/rsa-utils',
13
+ component: () => import('@/views/utils/rsa-utils.vue')
14
+ },
15
+ {
16
+ path: '/utils/sso-utils',
17
+ component: () => import('@/views/utils/sso-utils.vue')
18
+ },
19
+ {
20
+ path: '/utils/message-utils',
21
+ component: () => import('@/views/utils/message-utils.vue')
22
+ },
6
23
 
24
+ ...getExceptionRoutes()
7
25
  ]
8
26
  })
9
27