mirror of
https://github.com/vbenjs/vben-admin-thin-next.git
synced 2025-01-24 02:00:22 +08:00
feat: the cache can be configured to be encrypted
This commit is contained in:
parent
3a132f3f4f
commit
234c1d1fae
@ -1,5 +1,10 @@
|
|||||||
## Wip
|
## Wip
|
||||||
|
|
||||||
|
### ✨ Features
|
||||||
|
|
||||||
|
- 缓存可以配置是否加密
|
||||||
|
- 多语言支持
|
||||||
|
|
||||||
### 🎫 Chores
|
### 🎫 Chores
|
||||||
|
|
||||||
- 移除 messageSetting 配置
|
- 移除 messageSetting 配置
|
||||||
|
@ -37,16 +37,16 @@
|
|||||||
"vditor": "^3.6.3",
|
"vditor": "^3.6.3",
|
||||||
"vue": "^3.0.2",
|
"vue": "^3.0.2",
|
||||||
"vue-i18n": "^9.0.0-beta.8",
|
"vue-i18n": "^9.0.0-beta.8",
|
||||||
"vue-router": "^4.0.0-rc.3",
|
"vue-router": "^4.0.0-rc.5",
|
||||||
"vuex": "^4.0.0-rc.1",
|
"vuex": "^4.0.0-rc.1",
|
||||||
"vuex-module-decorators": "^1.0.1",
|
"vuex-module-decorators": "^1.0.1",
|
||||||
"xlsx": "^0.16.8",
|
"xlsx": "^0.16.9",
|
||||||
"zxcvbn": "^4.4.2"
|
"zxcvbn": "^4.4.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^11.0.0",
|
"@commitlint/cli": "^11.0.0",
|
||||||
"@commitlint/config-conventional": "^11.0.0",
|
"@commitlint/config-conventional": "^11.0.0",
|
||||||
"@iconify/json": "^1.1.261",
|
"@iconify/json": "^1.1.262",
|
||||||
"@ls-lint/ls-lint": "^1.9.2",
|
"@ls-lint/ls-lint": "^1.9.2",
|
||||||
"@purge-icons/generated": "^0.4.1",
|
"@purge-icons/generated": "^0.4.1",
|
||||||
"@types/echarts": "^4.9.1",
|
"@types/echarts": "^4.9.1",
|
||||||
@ -72,7 +72,7 @@
|
|||||||
"cross-env": "^7.0.2",
|
"cross-env": "^7.0.2",
|
||||||
"dot-prop": "^6.0.1",
|
"dot-prop": "^6.0.1",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"eslint": "^7.13.0",
|
"eslint": "^7.14.0",
|
||||||
"eslint-config-prettier": "^6.15.0",
|
"eslint-config-prettier": "^6.15.0",
|
||||||
"eslint-plugin-prettier": "^3.1.4",
|
"eslint-plugin-prettier": "^3.1.4",
|
||||||
"eslint-plugin-vue": "^7.1.0",
|
"eslint-plugin-vue": "^7.1.0",
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
import AppLocalPicker from './src/AppLocalPicker.vue';
|
import AppLocalPicker from './src/AppLocalPicker.vue';
|
||||||
|
import AppFooterToolbar from './src/AppFooterToolbar.vue';
|
||||||
|
import { withInstall } from '../util';
|
||||||
|
|
||||||
export { AppLocalPicker };
|
export { AppLocalPicker, AppFooterToolbar };
|
||||||
|
|
||||||
|
export default withInstall(AppLocalPicker, AppFooterToolbar);
|
||||||
|
@ -10,11 +10,14 @@
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, computed, unref } from 'vue';
|
import { defineComponent, computed, unref } from 'vue';
|
||||||
|
|
||||||
import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '/@/enums/appEnum';
|
import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '/@/enums/appEnum';
|
||||||
|
|
||||||
import { appStore } from '/@/store/modules/app';
|
import { appStore } from '/@/store/modules/app';
|
||||||
import { menuStore } from '/@/store/modules/menu';
|
import { menuStore } from '/@/store/modules/menu';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'AppFooter',
|
name: 'AppFooterToolbar',
|
||||||
setup() {
|
setup() {
|
||||||
const getMiniWidth = computed(() => {
|
const getMiniWidth = computed(() => {
|
||||||
const {
|
const {
|
@ -1,8 +1,7 @@
|
|||||||
import type { App } from 'vue';
|
|
||||||
import Authority from './src/index.vue';
|
import Authority from './src/index.vue';
|
||||||
|
|
||||||
export default (app: App): void => {
|
import { withInstall } from '../util';
|
||||||
app.component(Authority.name, Authority);
|
|
||||||
};
|
export default withInstall(Authority);
|
||||||
|
|
||||||
export { Authority };
|
export { Authority };
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export { default as AppFooter } from './src/index.vue';
|
|
@ -1,6 +1,5 @@
|
|||||||
import Icon from './Icon/index';
|
import Icon from './Icon/index';
|
||||||
import Button from './Button/index.vue';
|
import Button from './Button/index.vue';
|
||||||
import { AppFooter } from './Footer';
|
|
||||||
import {
|
import {
|
||||||
// Need
|
// Need
|
||||||
Button as AntButton,
|
Button as AntButton,
|
||||||
@ -35,7 +34,7 @@ import {
|
|||||||
} from 'ant-design-vue';
|
} from 'ant-design-vue';
|
||||||
import { getApp } from '/@/setup/App';
|
import { getApp } from '/@/setup/App';
|
||||||
|
|
||||||
const compList = [Icon, Button, AntButton.Group, AppFooter];
|
const compList = [Icon, Button, AntButton.Group];
|
||||||
|
|
||||||
// Fix hmr multiple registered components
|
// Fix hmr multiple registered components
|
||||||
let registered = false;
|
let registered = false;
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
import type { VNodeChild } from 'vue';
|
import type { VNodeChild } from 'vue';
|
||||||
|
import type { App, Component } from 'vue';
|
||||||
|
|
||||||
|
export function withInstall(...components: Component[]) {
|
||||||
|
return (app: App) => {
|
||||||
|
components.forEach((comp) => {
|
||||||
|
comp.name && app.component(comp.name, comp);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function convertToUnit(
|
export function convertToUnit(
|
||||||
str: string | number | null | undefined,
|
str: string | number | null | undefined,
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
// System default cache time, in seconds
|
|
||||||
export const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description:
|
|
||||||
*/
|
|
||||||
export const storageCipher = {
|
|
||||||
key: '_12345678901234@',
|
|
||||||
iv: '@12345678901234_',
|
|
||||||
};
|
|
13
src/settings/encryptionSetting.ts
Normal file
13
src/settings/encryptionSetting.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { isDevMode } from '/@/utils/env';
|
||||||
|
|
||||||
|
// System default cache time, in seconds
|
||||||
|
export const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7;
|
||||||
|
|
||||||
|
// aes encryption key
|
||||||
|
export const cacheCipher = {
|
||||||
|
key: '_12345678901234@',
|
||||||
|
iv: '@12345678901234_',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Whether the system cache is encrypted using aes
|
||||||
|
export const enableStorageEncryption = !isDevMode();
|
78
src/utils/cache/cookie.ts
vendored
Normal file
78
src/utils/cache/cookie.ts
vendored
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import { DEFAULT_CACHE_TIME } from '../../settings/encryptionSetting';
|
||||||
|
import { getStorageShortName } from '/@/utils/helper/envHelper';
|
||||||
|
import { cacheCipher } from '/@/settings/encryptionSetting';
|
||||||
|
import Encryption from '/@/utils/encryption/aesEncryption';
|
||||||
|
|
||||||
|
export default class WebCookie {
|
||||||
|
private encryption: Encryption;
|
||||||
|
private hasEncrypt: boolean;
|
||||||
|
|
||||||
|
constructor(hasEncrypt = true, key = cacheCipher.key, iv = cacheCipher.iv) {
|
||||||
|
const encryption = new Encryption({ key, iv });
|
||||||
|
this.encryption = encryption;
|
||||||
|
this.hasEncrypt = hasEncrypt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getKey(key: string) {
|
||||||
|
return `${getStorageShortName()}${key}`.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add cookie
|
||||||
|
* @param name cookie key
|
||||||
|
* @param value cookie value
|
||||||
|
* @param expire
|
||||||
|
* If the expiration time is not set, the default management browser will automatically delete
|
||||||
|
* e.g:
|
||||||
|
* cookieData.set('name','value',)
|
||||||
|
*/
|
||||||
|
setCookie(key: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) {
|
||||||
|
value = this.hasEncrypt ? this.encryption.encryptByAES(JSON.stringify(value)) : value;
|
||||||
|
document.cookie = this.getKey(key) + '=' + value + '; Max-Age=' + expire;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the cook value according to the key
|
||||||
|
* @param key cookie key
|
||||||
|
*/
|
||||||
|
getCookie(key: string) {
|
||||||
|
const arr = document.cookie.split('; ');
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
const arr2 = arr[i].split('=');
|
||||||
|
if (arr2[0] === this.getKey(key)) {
|
||||||
|
let message: any = null;
|
||||||
|
const str = arr2[1];
|
||||||
|
if (this.hasEncrypt && str) {
|
||||||
|
message = this.encryption.decryptByAES(str);
|
||||||
|
try {
|
||||||
|
return JSON.parse(message);
|
||||||
|
} catch (e) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete cookie based on cookie key
|
||||||
|
* @param key cookie key
|
||||||
|
*/
|
||||||
|
removeCookie(key: string) {
|
||||||
|
this.setCookie(key, 1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clear cookie
|
||||||
|
*/
|
||||||
|
clearCookie(): void {
|
||||||
|
const keys = document.cookie.match(/[^ =;]+(?==)/g);
|
||||||
|
if (keys) {
|
||||||
|
for (let i = keys.length; i--; ) {
|
||||||
|
document.cookie = keys[i] + '=0;expires=' + new Date(0).toUTCString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,20 @@
|
|||||||
import { getStorageShortName } from '/@/utils/helper/envHelper';
|
import { getStorageShortName } from '/@/utils/helper/envHelper';
|
||||||
import { createStorage as create } from './Storage';
|
import { createStorage as create } from './storageCache';
|
||||||
|
import { enableStorageEncryption } from '/@/settings/encryptionSetting';
|
||||||
// debug模式下不加密
|
|
||||||
|
|
||||||
const createOptions = (storage = sessionStorage) => {
|
const createOptions = (storage = sessionStorage) => {
|
||||||
return {
|
return {
|
||||||
|
// No encryption in debug mode
|
||||||
|
hasEncrypt: enableStorageEncryption,
|
||||||
storage,
|
storage,
|
||||||
prefixKey: getStorageShortName(),
|
prefixKey: getStorageShortName(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WebStorage = create(createOptions());
|
export const WebStorage = create(createOptions());
|
||||||
|
|
||||||
export const createStorage = (storage: Storage = sessionStorage) => {
|
export const createStorage = (storage: Storage = sessionStorage) => {
|
||||||
return create(createOptions(storage))!;
|
return create(createOptions(storage))!;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default WebStorage;
|
export default WebStorage;
|
108
src/utils/cache/storageCache.ts
vendored
Normal file
108
src/utils/cache/storageCache.ts
vendored
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
import { DEFAULT_CACHE_TIME } from '/@/settings/encryptionSetting';
|
||||||
|
import { cacheCipher } from '/@/settings/encryptionSetting';
|
||||||
|
import Encryption, { EncryptionParams } from '/@/utils/encryption/aesEncryption';
|
||||||
|
|
||||||
|
export interface CreateStorageParams extends EncryptionParams {
|
||||||
|
storage: Storage;
|
||||||
|
|
||||||
|
hasEncrypt: boolean;
|
||||||
|
}
|
||||||
|
export const createStorage = ({
|
||||||
|
prefixKey = '',
|
||||||
|
storage = sessionStorage,
|
||||||
|
key = cacheCipher.key,
|
||||||
|
iv = cacheCipher.iv,
|
||||||
|
hasEncrypt = true,
|
||||||
|
} = {}) => {
|
||||||
|
if (hasEncrypt && [key.length, iv.length].some((item) => item !== 16)) {
|
||||||
|
throw new Error('When hasEncrypt is true, the key or iv must be 16 bits!');
|
||||||
|
}
|
||||||
|
|
||||||
|
const encryption = new Encryption({ key, iv });
|
||||||
|
|
||||||
|
/**
|
||||||
|
*Cache class
|
||||||
|
*Construction parameters can be passed into sessionStorage, localStorage,
|
||||||
|
* @class Cache
|
||||||
|
* @example
|
||||||
|
*/
|
||||||
|
const WebStorage = class WebStorage {
|
||||||
|
private storage: Storage;
|
||||||
|
private prefixKey?: string;
|
||||||
|
private encryption: Encryption;
|
||||||
|
private hasEncrypt: boolean;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} storage
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
this.storage = storage;
|
||||||
|
this.prefixKey = prefixKey;
|
||||||
|
this.encryption = encryption;
|
||||||
|
this.hasEncrypt = hasEncrypt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getKey(key: string) {
|
||||||
|
return `${this.prefixKey}${key}`.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Set cache
|
||||||
|
* @param {string} key
|
||||||
|
* @param {*} value
|
||||||
|
* @expire Expiration time in seconds
|
||||||
|
* @memberof Cache
|
||||||
|
*/
|
||||||
|
set(key: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) {
|
||||||
|
const stringData = JSON.stringify({
|
||||||
|
value,
|
||||||
|
expire: expire !== null ? new Date().getTime() + expire * 1000 : null,
|
||||||
|
});
|
||||||
|
const stringifyValue = this.hasEncrypt
|
||||||
|
? this.encryption.encryptByAES(stringData)
|
||||||
|
: stringData;
|
||||||
|
this.storage.setItem(this.getKey(key), stringifyValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*Read cache
|
||||||
|
* @param {string} key
|
||||||
|
* @memberof Cache
|
||||||
|
*/
|
||||||
|
get(key: string, def: any = null): any {
|
||||||
|
const item = this.storage.getItem(this.getKey(key));
|
||||||
|
if (item) {
|
||||||
|
try {
|
||||||
|
const decItem = this.hasEncrypt ? this.encryption.decryptByAES(item) : item;
|
||||||
|
const data = JSON.parse(decItem);
|
||||||
|
const { value, expire } = data;
|
||||||
|
if (expire === null || expire >= new Date().getTime()) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
this.remove(this.getKey(key));
|
||||||
|
} catch (e) {
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete cache based on key
|
||||||
|
* @param {string} key
|
||||||
|
* @memberof Cache
|
||||||
|
*/
|
||||||
|
remove(key: string) {
|
||||||
|
this.storage.removeItem(this.getKey(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all caches of this instance
|
||||||
|
*/
|
||||||
|
clear(): void {
|
||||||
|
this.storage.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return new WebStorage();
|
||||||
|
};
|
35
src/utils/encryption/aesEncryption.ts
Normal file
35
src/utils/encryption/aesEncryption.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import CryptoES from 'crypto-es';
|
||||||
|
export interface EncryptionParams {
|
||||||
|
key: string;
|
||||||
|
iv: string;
|
||||||
|
}
|
||||||
|
export class Encryption {
|
||||||
|
private key;
|
||||||
|
|
||||||
|
private iv;
|
||||||
|
|
||||||
|
constructor(opt: EncryptionParams) {
|
||||||
|
const { key, iv } = opt;
|
||||||
|
this.key = CryptoES.enc.Utf8.parse(key);
|
||||||
|
this.iv = CryptoES.enc.Utf8.parse(iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
get getOpt(): CryptoES.lib.CipherCfg {
|
||||||
|
return {
|
||||||
|
mode: CryptoES.mode.CBC as any,
|
||||||
|
padding: CryptoES.pad.Pkcs7,
|
||||||
|
iv: this.iv,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptByAES(str: string) {
|
||||||
|
const encrypted = CryptoES.AES.encrypt(str, this.key, this.getOpt);
|
||||||
|
return encrypted.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
decryptByAES(str: string) {
|
||||||
|
const decrypted = CryptoES.AES.decrypt(str, this.key, this.getOpt);
|
||||||
|
return decrypted.toString(CryptoES.enc.Utf8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default Encryption;
|
@ -1,4 +1,4 @@
|
|||||||
import { dataURLtoBlob, urlToBase64 } from './base64';
|
import { dataURLtoBlob, urlToBase64 } from './base64Conver';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download online pictures
|
* Download online pictures
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createStorage } from '/@/utils/storage';
|
import { createStorage } from '/@/utils/cache';
|
||||||
import { isIeFn } from '/@/utils/browser';
|
import { isIeFn } from '/@/utils/browser';
|
||||||
|
|
||||||
import { BASE_LOCAL_CACHE_KEY, BASE_SESSION_CACHE_KEY } from '/@/enums/cacheEnum';
|
import { BASE_LOCAL_CACHE_KEY, BASE_SESSION_CACHE_KEY } from '/@/enums/cacheEnum';
|
||||||
|
@ -1,138 +0,0 @@
|
|||||||
import { DEFAULT_CACHE_TIME } from '/@/settings/cipherSetting';
|
|
||||||
|
|
||||||
// import { EncryptionParams } from '/@/utils/cipher/aesEncryption';
|
|
||||||
export interface CreateStorageParams {
|
|
||||||
storage: Storage;
|
|
||||||
hasEncrypt: boolean;
|
|
||||||
}
|
|
||||||
export const createStorage = ({ prefixKey = '', storage = sessionStorage } = {}) => {
|
|
||||||
/**
|
|
||||||
*缓存类
|
|
||||||
*构造参数可以传入 sessionStorage,localStorage,
|
|
||||||
* @class Cache
|
|
||||||
* @example
|
|
||||||
*/
|
|
||||||
const WebStorage = class WebStorage {
|
|
||||||
private storage: Storage;
|
|
||||||
private prefixKey?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {*} storage
|
|
||||||
*/
|
|
||||||
constructor() {
|
|
||||||
this.storage = storage;
|
|
||||||
this.prefixKey = prefixKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getKey(key: string) {
|
|
||||||
return `${this.prefixKey}${key}`.toUpperCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* 设置缓存
|
|
||||||
* @param {string} key 缓存键
|
|
||||||
* @param {*} value 缓存值
|
|
||||||
* @expire 过期时间 单位秒
|
|
||||||
* @memberof Cache
|
|
||||||
*/
|
|
||||||
set(key: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) {
|
|
||||||
const stringData = JSON.stringify({
|
|
||||||
value,
|
|
||||||
expire: expire !== null ? new Date().getTime() + expire * 1000 : null,
|
|
||||||
});
|
|
||||||
this.storage.setItem(this.getKey(key), stringData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*读取缓存
|
|
||||||
* @param {string} key 缓存键
|
|
||||||
* @returns 缓存值
|
|
||||||
* @memberof Cache
|
|
||||||
*/
|
|
||||||
get(key: string, def: any = null): any {
|
|
||||||
const item = this.storage.getItem(this.getKey(key));
|
|
||||||
if (item) {
|
|
||||||
try {
|
|
||||||
const data = JSON.parse(item);
|
|
||||||
const { value, expire } = data;
|
|
||||||
if (expire === null || expire >= new Date().getTime()) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
this.remove(this.getKey(key));
|
|
||||||
} catch (e) {
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*删除缓存
|
|
||||||
* @param {string} key 缓存键
|
|
||||||
* @memberof Cache
|
|
||||||
*/
|
|
||||||
remove(key: string) {
|
|
||||||
this.storage.removeItem(this.getKey(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*删除该实例所有缓存
|
|
||||||
* @memberof Cache
|
|
||||||
*/
|
|
||||||
clear(): void {
|
|
||||||
this.storage.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加cookie
|
|
||||||
* @param name cookie名字
|
|
||||||
* @param value cookie内容
|
|
||||||
* @param expire
|
|
||||||
* 如果过期时间未设置,默认管理浏览器自动删除
|
|
||||||
* 例子:
|
|
||||||
* cookieData.set('name','value',)
|
|
||||||
*/
|
|
||||||
setCookie(name: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) {
|
|
||||||
document.cookie = this.getKey(name) + '=' + value + '; Max-Age=' + expire;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据名字获取cooki值
|
|
||||||
* @param name cookie名
|
|
||||||
* @returns {*} cookie值
|
|
||||||
*/
|
|
||||||
getCookie(name: string) {
|
|
||||||
const arr = document.cookie.split('; ');
|
|
||||||
for (let i = 0; i < arr.length; i++) {
|
|
||||||
const arr2 = arr[i].split('=');
|
|
||||||
if (arr2[0] === this.getKey(name)) {
|
|
||||||
return arr2[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据cookie名字删除cookie
|
|
||||||
* @param name cookie名字
|
|
||||||
*/
|
|
||||||
removeCookie(key: string) {
|
|
||||||
this.setCookie(key, 1, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
clearCookie(): void {
|
|
||||||
const keys = document.cookie.match(/[^ =;]+(?==)/g);
|
|
||||||
if (keys) {
|
|
||||||
for (let i = keys.length; i--; ) {
|
|
||||||
document.cookie = keys[i] + '=0;expires=' + new Date(0).toUTCString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return new WebStorage();
|
|
||||||
};
|
|
@ -16,21 +16,23 @@
|
|||||||
</a-card>
|
</a-card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<app-footer>
|
<AppFooterToolbar>
|
||||||
<template #right>
|
<template #right>
|
||||||
<a-button type="primary" @click="submitAll">提交</a-button>
|
<a-button type="primary" @click="submitAll">提交</a-button>
|
||||||
</template>
|
</template>
|
||||||
</app-footer>
|
</AppFooterToolbar>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { BasicForm, useForm } from '/@/components/Form';
|
import { BasicForm, useForm } from '/@/components/Form';
|
||||||
import { defineComponent, ref } from 'vue';
|
import { defineComponent, ref } from 'vue';
|
||||||
import PersonTable from './PersonTable.vue';
|
import PersonTable from './PersonTable.vue';
|
||||||
|
import { AppFooterToolbar } from '/@/components/Application';
|
||||||
|
|
||||||
import { schemas, taskSchemas } from './data';
|
import { schemas, taskSchemas } from './data';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { BasicForm, PersonTable },
|
components: { BasicForm, PersonTable, AppFooterToolbar },
|
||||||
setup() {
|
setup() {
|
||||||
const tableRef = ref<{ getDataSource: () => any } | null>(null);
|
const tableRef = ref<{ getDataSource: () => any } | null>(null);
|
||||||
|
|
||||||
|
38
yarn.lock
38
yarn.lock
@ -1050,10 +1050,10 @@
|
|||||||
resolved "https://registry.npmjs.org/@iconify/iconify/-/iconify-2.0.0-rc.2.tgz#c4a95ddc06ca9b9496df03604e66fdefb39f4c4b"
|
resolved "https://registry.npmjs.org/@iconify/iconify/-/iconify-2.0.0-rc.2.tgz#c4a95ddc06ca9b9496df03604e66fdefb39f4c4b"
|
||||||
integrity sha512-BybEHU5/I9EQ0CcwKAqmreZ2bMnAXrqLCTptAc6vPetHMbrXdZfejP5mt57e/8PNSt/qE7BHniU5PCYA+PGIHw==
|
integrity sha512-BybEHU5/I9EQ0CcwKAqmreZ2bMnAXrqLCTptAc6vPetHMbrXdZfejP5mt57e/8PNSt/qE7BHniU5PCYA+PGIHw==
|
||||||
|
|
||||||
"@iconify/json@^1.1.261":
|
"@iconify/json@^1.1.262":
|
||||||
version "1.1.261"
|
version "1.1.262"
|
||||||
resolved "https://registry.npmjs.org/@iconify/json/-/json-1.1.261.tgz#9a6986b6b36d77ca147c4be149db9a43280a8fb2"
|
resolved "https://registry.npmjs.org/@iconify/json/-/json-1.1.262.tgz#a67067bad418d59c729ec514e3aa629d0ab3710b"
|
||||||
integrity sha512-lnRk1OBqNxZ593oZyOXEMp/O+cr+lF54xaW6+F3krWdWhzxQgi0W1ffzvdiLySdbTEorQ2NvVU4e0+Af27rXPA==
|
integrity sha512-PfKUS/Ue9Rn2oO0ez/Yj4Cdodvv6vDHgPjIZNSElu2+149CYaPmWahHI87ZY+r8l3bijPIu6+blyAixdJtPPMg==
|
||||||
|
|
||||||
"@koa/cors@^3.1.0":
|
"@koa/cors@^3.1.0":
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
@ -3418,10 +3418,10 @@ eslint-visitor-keys@^2.0.0:
|
|||||||
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8"
|
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8"
|
||||||
integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
|
integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
|
||||||
|
|
||||||
eslint@^7.13.0:
|
eslint@^7.14.0:
|
||||||
version "7.13.0"
|
version "7.14.0"
|
||||||
resolved "https://registry.npmjs.org/eslint/-/eslint-7.13.0.tgz#7f180126c0dcdef327bfb54b211d7802decc08da"
|
resolved "https://registry.npmjs.org/eslint/-/eslint-7.14.0.tgz#2d2cac1d28174c510a97b377f122a5507958e344"
|
||||||
integrity sha512-uCORMuOO8tUzJmsdRtrvcGq5qposf7Rw0LwkTJkoDbOycVQtQjmnhZSuLQnozLE4TmAzlMVV45eCHmQ1OpDKUQ==
|
integrity sha512-5YubdnPXrlrYAFCKybPuHIAH++PINe1pmKNc5wQRB9HSbqIK1ywAnntE3Wwua4giKu0bjligf1gLF6qxMGOYRA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame" "^7.0.0"
|
"@babel/code-frame" "^7.0.0"
|
||||||
"@eslint/eslintrc" "^0.2.1"
|
"@eslint/eslintrc" "^0.2.1"
|
||||||
@ -3686,6 +3686,11 @@ fastq@^1.6.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
reusify "^1.0.4"
|
reusify "^1.0.4"
|
||||||
|
|
||||||
|
fflate@^0.3.8:
|
||||||
|
version "0.3.10"
|
||||||
|
resolved "https://registry.npmjs.org/fflate/-/fflate-0.3.10.tgz#0e581839a53203d2eeac7e61ce3652d855e24dcd"
|
||||||
|
integrity sha512-s5j69APkUPPbzdI20Ix4pPtQP+1Qi58YcFRpE7aO/P1kEywUYjbl2RjZRVEMdnySO9pr4MB0BHPbxkiahrtD/Q==
|
||||||
|
|
||||||
figures@^2.0.0:
|
figures@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
|
resolved "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
|
||||||
@ -8196,10 +8201,10 @@ vue-i18n@^9.0.0-beta.8:
|
|||||||
dependencies:
|
dependencies:
|
||||||
source-map "0.6.1"
|
source-map "0.6.1"
|
||||||
|
|
||||||
vue-router@^4.0.0-rc.3:
|
vue-router@^4.0.0-rc.5:
|
||||||
version "4.0.0-rc.3"
|
version "4.0.0-rc.5"
|
||||||
resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.0.0-rc.3.tgz#70d18e90030bc6a25e81a30401d673223998ec6b"
|
resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.0.0-rc.5.tgz#191d32e3d5276641ff21e881d34e33a71dc6e8f0"
|
||||||
integrity sha512-NnPqWIfanEhJC4wu8BEFBmnEDIrx9ST0/HtmBiE+oV2MQlhyRk1TmdttWwVqx6Sh7kONsrI10GQV9l3YEkcWXg==
|
integrity sha512-Q8Tt6VGwGMN5qASeIdjSydU3uRADK9AUkqnbnzmTz+zZKS0W6GZOAuP235lf3y5/MqEFSKRJGaTWPEY0t+Rjmg==
|
||||||
|
|
||||||
vue-types@^3.0.0:
|
vue-types@^3.0.0:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
@ -8480,10 +8485,10 @@ ws@^7.3.1:
|
|||||||
resolved "https://registry.npmjs.org/ws/-/ws-7.4.0.tgz#a5dd76a24197940d4a8bb9e0e152bb4503764da7"
|
resolved "https://registry.npmjs.org/ws/-/ws-7.4.0.tgz#a5dd76a24197940d4a8bb9e0e152bb4503764da7"
|
||||||
integrity sha512-kyFwXuV/5ymf+IXhS6f0+eAFvydbaBW3zjpT6hUdAh/hbVjTIB5EHBGi0bPoCLSK2wcuz3BrEkB9LrYv1Nm4NQ==
|
integrity sha512-kyFwXuV/5ymf+IXhS6f0+eAFvydbaBW3zjpT6hUdAh/hbVjTIB5EHBGi0bPoCLSK2wcuz3BrEkB9LrYv1Nm4NQ==
|
||||||
|
|
||||||
xlsx@^0.16.8:
|
xlsx@^0.16.9:
|
||||||
version "0.16.8"
|
version "0.16.9"
|
||||||
resolved "https://registry.npmjs.org/xlsx/-/xlsx-0.16.8.tgz#5546de9b0ba15169b36770d4e43b24790d3ff1b8"
|
resolved "https://registry.npmjs.org/xlsx/-/xlsx-0.16.9.tgz#dacd5bb46bda6dd3743940c9c3dc1e2171826256"
|
||||||
integrity sha512-qWub4YCn0xLEGHI7WWhk6IJ73MDu7sPSJQImxN6/LiI8wsHi0hUhICEDbyqBT+jgFgORZxrii0HvhNSwBNAPoQ==
|
integrity sha512-gxi1I3EasYvgCX1vN9pGyq920Ron4NO8PNfhuoA3Hpq6Y8f0ECXiy4OLrK4QZBnj1jx3QD+8Fq5YZ/3mPZ5iXw==
|
||||||
dependencies:
|
dependencies:
|
||||||
adler-32 "~1.2.0"
|
adler-32 "~1.2.0"
|
||||||
cfb "^1.1.4"
|
cfb "^1.1.4"
|
||||||
@ -8491,6 +8496,7 @@ xlsx@^0.16.8:
|
|||||||
commander "~2.17.1"
|
commander "~2.17.1"
|
||||||
crc-32 "~1.2.0"
|
crc-32 "~1.2.0"
|
||||||
exit-on-epipe "~1.0.1"
|
exit-on-epipe "~1.0.1"
|
||||||
|
fflate "^0.3.8"
|
||||||
ssf "~0.11.2"
|
ssf "~0.11.2"
|
||||||
wmf "~1.0.1"
|
wmf "~1.0.1"
|
||||||
word "~0.3.0"
|
word "~0.3.0"
|
||||||
|
Loading…
Reference in New Issue
Block a user