提交 b7ce74ab 作者: Vben

refactor: refactor the project to solve the hot update problem caused by…

refactor: refactor the project to solve the hot update problem caused by circular dependencies close #301
上级 371af18d
......@@ -138,6 +138,7 @@
"vetur.format.defaultFormatter.ts": "prettier-tslint",
"vetur.format.defaultFormatter.js": "prettier",
"vetur.languageFeatures.codeActions": false,
"vetur.validation.script": false,
"vetur.format.defaultFormatterOptions": {
"js-beautify-html": {
"wrap_attributes": "force-expand-multiline"
......@@ -188,6 +189,11 @@
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"[vue]": {
"editor.codeActionsOnSave": {
"source.fixAll.eslint": false
}
},
"i18n-ally.localesPaths": ["src/locales/lang"],
"i18n-ally.keystyle": "nested",
"i18n-ally.sortKeys": true,
......
## Wip
### ✨ Refactor
- 重构项目以解决循环依赖项导致的热更新问题
## 2.0.3 (2021-03-07)
### ✨ Features
......
......@@ -53,7 +53,7 @@
"devDependencies": {
"@commitlint/cli": "^12.0.1",
"@commitlint/config-conventional": "^12.0.1",
"@iconify/json": "^1.1.312",
"@iconify/json": "^1.1.313",
"@ls-lint/ls-lint": "^1.9.2",
"@purge-icons/generated": "^0.7.0",
"@types/crypto-js": "^4.0.1",
......@@ -119,7 +119,7 @@
"resolutions": {
"//": "Used to install imagemin dependencies, because imagemin may not be installed in China.If it is abroad, you can delete it",
"bin-wrapper": "npm:bin-wrapper-china",
"esbuild": "0.8.56",
"esbuild": "0.8.57",
"rollup": "2.40.0"
},
"repository": {
......
......@@ -5,6 +5,7 @@ import {
GetUserInfoByUserIdParams,
GetUserInfoByUserIdModel,
} from './model/userModel';
import { ErrorMessageMode } from '/@/utils/http/axios/types';
enum Api {
......
......@@ -5,10 +5,12 @@ import type {
ColumnProps,
TableRowSelection as ITableRowSelection,
} from 'ant-design-vue/lib/table/interface';
import { ComponentType } from './componentType';
import { VueNode } from '/@/utils/propTypes';
// import { ColumnProps } from './column';
export declare type SortOrder = 'ascend' | 'descend';
export interface TableCurrentDataSource<T = Recordable> {
currentDataSource: T[];
}
......
......@@ -5,12 +5,13 @@
*/
import type { App, Directive, DirectiveBinding } from 'vue';
import { appStore } from '/@/store/modules/app';
import projectSetting from '/@/settings/projectSetting';
import { usePermission } from '/@/hooks/web/usePermission';
import { PermissionModeEnum } from '/@/enums/appEnum';
const { hasPermission } = usePermission();
function isAuth(el: Element, binding: any) {
const { hasPermission } = usePermission();
const value = binding.value;
if (!value) return;
if (!hasPermission(value)) {
......@@ -19,7 +20,7 @@ function isAuth(el: Element, binding: any) {
}
function isBackMode() {
return appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK;
return projectSetting.permissionMode === PermissionModeEnum.BACK;
}
const mounted = (el: Element, binding: DirectiveBinding<any>) => {
......
......@@ -9,6 +9,7 @@ import { useTabs } from './useTabs';
import router, { resetRouter } from '/@/router';
// import { RootRoute } from '/@/router/routes';
import projectSetting from '/@/settings/projectSetting';
import { PermissionModeEnum } from '/@/enums/appEnum';
import { RoleEnum } from '/@/enums/roleEnum';
......@@ -24,7 +25,7 @@ export function usePermission() {
async function togglePermissionMode() {
appStore.commitProjectConfigState({
permissionMode:
appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK
projectSetting.permissionMode === PermissionModeEnum.BACK
? PermissionModeEnum.ROLE
: PermissionModeEnum.BACK,
});
......@@ -51,7 +52,7 @@ export function usePermission() {
* Determine whether there is permission
*/
function hasPermission(value?: RoleEnum | RoleEnum[] | string | string[], def = true): boolean {
const permMode = appStore.getProjectConfig.permissionMode;
const permMode = projectSetting.permissionMode;
if (PermissionModeEnum.ROLE === permMode) {
// Visible by default
if (!value) {
......@@ -81,7 +82,7 @@ export function usePermission() {
* @param roles
*/
async function changeRole(roles: RoleEnum | RoleEnum[]): Promise<void> {
if (appStore.getProjectConfig.permissionMode !== PermissionModeEnum.ROLE) {
if (projectSetting.permissionMode !== PermissionModeEnum.ROLE) {
throw new Error(
'Please switch PermissionModeEnum to ROLE mode in the configuration to operate!'
);
......
......@@ -19,17 +19,23 @@
<script lang="ts">
import { defineComponent, unref } from 'vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { useI18n } from '/@/hooks/web/useI18n';
import { CopyOutlined, RedoOutlined } from '@ant-design/icons-vue';
import { appStore } from '/@/store/modules/app';
import defaultSetting from '/@/settings/projectSetting';
import { permissionStore } from '/@/store/modules/permission';
import { tabStore } from '/@/store/modules/tab';
import { userStore } from '/@/store/modules/user';
import { useDesign } from '/@/hooks/web/useDesign';
import { useI18n } from '/@/hooks/web/useI18n';
import { useMessage } from '/@/hooks/web/useMessage';
import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
import { updateColorWeak } from '/@/logics/theme/updateColorWeak';
import { updateGrayMode } from '/@/logics/theme/updateGrayMode';
import defaultSetting from '/@/settings/projectSetting';
export default defineComponent({
name: 'SettingFooter',
components: { CopyOutlined, RedoOutlined },
......@@ -63,6 +69,9 @@
function handleClearAndRedo() {
localStorage.clear();
appStore.resumeAllState();
permissionStore.commitResetState();
tabStore.commitResetState();
userStore.commitResetState();
location.reload();
}
return {
......
......@@ -3,17 +3,21 @@ import type { RouteLocation } from 'vue-router';
import { computed, ref, unref } from 'vue';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
import { tryTsxEmit } from '/@/utils/helper/vueHelper';
import { tabStore, PAGE_LAYOUT_KEY } from '/@/store/modules/tab';
import { useRouter } from 'vue-router';
import { useStore } from 'vuex';
const ParentLayoutName = 'ParentLayout';
const PAGE_LAYOUT_KEY = '__PAGE_LAYOUT__';
export function getKey(component: FunctionalComponent & { type: Indexable }, route: RouteLocation) {
return !!component?.type.parentView ? {} : { key: route.fullPath };
}
export function useCache(isPage: boolean) {
const { getters } = useStore();
const name = ref('');
const { currentRoute } = useRouter();
......@@ -38,7 +42,7 @@ export function useCache(isPage: boolean) {
if (!unref(getOpenKeepAlive)) {
return [];
}
const cached = tabStore.getCachedMapState;
const cached = getters['app-tab/getCachedMapState'];
if (isPage) {
// page Layout
......
......@@ -17,9 +17,11 @@ import { setupStore } from '/@/store';
import { setupErrorHandle } from '/@/logics/error-handle';
import { setupGlobDirectives } from '/@/directives';
import { setupI18n } from '/@/locales/setupI18n';
import { registerGlobComp } from '/@/components/registerGlobComp';
// router-guard
import '/@/router/guard';
// Register icon Sprite
import 'vite-plugin-svg-icons/register';
......@@ -32,6 +34,7 @@ import { isDevMode } from '/@/utils/env';
// Multilingual configuration
await setupI18n(app);
// Configure routing
setupRouter(app);
......
import { Router } from 'vue-router';
import router from '/@/router';
import { createProgressGuard } from './progressGuard';
import { createPermissionGuard } from './permissionGuard';
......@@ -10,14 +10,12 @@ import { createHttpGuard } from './httpGuard';
import { createPageGuard } from './pageGuard';
import { createStateGuard } from './stateGuard';
export function createGuard(router: Router) {
createPageGuard(router);
createPageLoadingGuard(router);
createHttpGuard(router);
createScrollGuard(router);
createMessageGuard(router);
createTitleGuard(router);
createProgressGuard(router);
createPermissionGuard(router);
createStateGuard(router);
}
createPageGuard(router);
createPageLoadingGuard(router);
createHttpGuard(router);
createScrollGuard(router);
createMessageGuard(router);
createTitleGuard(router);
createProgressGuard(router);
createPermissionGuard(router);
createStateGuard(router);
import type { Router } from 'vue-router';
import { appStore } from '/@/store/modules/app';
import { tabStore } from '/@/store/modules/tab';
import { userStore } from '/@/store/modules/user';
import { permissionStore } from '/@/store/modules/permission';
import { PageEnum } from '/@/enums/pageEnum';
import { removeTabChangeListener } from '/@/logics/mitt/tabChange';
......@@ -8,6 +11,9 @@ export function createStateGuard(router: Router) {
// Just enter the login page and clear the authentication information
if (to.path === PageEnum.BASE_LOGIN) {
appStore.resumeAllState();
permissionStore.commitResetState();
tabStore.commitResetState();
userStore.commitResetState();
removeTabChangeListener();
}
});
......
......@@ -3,7 +3,6 @@ import type { App } from 'vue';
import { createRouter, createWebHashHistory } from 'vue-router';
import { createGuard } from './guard';
import { basicRoutes, LoginRoute } from './routes';
import { REDIRECT_NAME } from './constant';
......@@ -30,7 +29,6 @@ export function resetRouter() {
// config router
export function setupRouter(app: App<Element>) {
app.use(router);
createGuard(router);
}
export default router;
......@@ -10,10 +10,6 @@ import { Persistent } from '/@/utils/cache/persistent';
import { deepMerge } from '/@/utils';
import { resetRouter } from '/@/router';
import { permissionStore } from './permission';
import { tabStore } from './tab';
import { userStore } from './user';
export interface LockInfo {
pwd: string | undefined;
......@@ -66,10 +62,6 @@ export default class App extends VuexModule {
async resumeAllState() {
resetRouter();
Persistent.clearAll();
permissionStore.commitResetState();
tabStore.commitResetState();
userStore.commitResetState();
}
@Action
......
import type { LockInfo } from '/@/store/types';
import { VuexModule, getModule, Module, Mutation, Action } from 'vuex-module-decorators';
import store from '/@/store';
......@@ -8,11 +10,6 @@ import { Persistent } from '/@/utils/cache/persistent';
import { userStore } from './user';
export interface LockInfo {
pwd: string | undefined;
isLock: boolean;
}
const NAME = 'app-lock';
hotModuleUnregisterModule(NAME);
@Module({ dynamic: true, namespaced: true, store, name: NAME })
......
import { toRaw } from 'vue';
import type { RouteLocationNormalized, RouteLocationRaw } from 'vue-router';
import { unref } from 'vue';
import { toRaw, unref } from 'vue';
import { Action, Module, Mutation, VuexModule, getModule } from 'vuex-module-decorators';
import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
......@@ -9,8 +9,8 @@ import { PageEnum } from '/@/enums/pageEnum';
import store from '/@/store';
import router from '/@/router';
import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/constant';
import { RouteLocationNormalized, RouteLocationRaw } from 'vue-router';
import { getRoute } from '/@/router/helper/routeHelper';
import { useGo, useRedo } from '/@/hooks/web/usePage';
import { cloneDeep } from 'lodash-es';
......
......@@ -3,6 +3,7 @@ import type {
GetUserInfoByUserIdModel,
GetUserInfoByUserIdParams,
} from '/@/api/sys/model/userModel';
import type { UserInfo } from '/@/store/types';
import store from '/@/store/index';
import { VuexModule, Module, getModule, Mutation, Action } from 'vuex-module-decorators';
......@@ -10,7 +11,7 @@ import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
import { PageEnum } from '/@/enums/pageEnum';
import { RoleEnum } from '/@/enums/roleEnum';
import { CacheTypeEnum, ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum';
import { ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum';
import { useMessage } from '/@/hooks/web/useMessage';
......@@ -18,29 +19,13 @@ import router from '/@/router';
import { loginApi, getUserInfoById } from '/@/api/sys/user';
import { Persistent, BasicKeys } from '/@/utils/cache/persistent';
import { useI18n } from '/@/hooks/web/useI18n';
import { ErrorMessageMode } from '/@/utils/http/axios/types';
import projectSetting from '/@/settings/projectSetting';
export type UserInfo = Omit<GetUserInfoByUserIdModel, 'roles'>;
const { permissionCacheType } = projectSetting;
const isLocal = permissionCacheType === CacheTypeEnum.LOCAL;
import { getAuthCache, setAuthCache } from '/@/utils/auth/index';
const NAME = 'app-user';
hotModuleUnregisterModule(NAME);
function getCache<T>(key: BasicKeys) {
const fn = isLocal ? Persistent.getLocal : Persistent.getSession;
return fn(key) as T;
}
function setCache(key: BasicKeys, value) {
const fn = isLocal ? Persistent.setLocal : Persistent.setSession;
return fn(key, value);
}
@Module({ namespaced: true, name: NAME, dynamic: true, store })
class User extends VuexModule {
// user info
......@@ -53,15 +38,15 @@ class User extends VuexModule {
private roleListState: RoleEnum[] = [];
get getUserInfoState(): UserInfo {
return this.userInfoState || getCache<UserInfo>(USER_INFO_KEY) || {};
return this.userInfoState || getAuthCache<UserInfo>(USER_INFO_KEY) || {};
}
get getTokenState(): string {
return this.tokenState || getCache<string>(TOKEN_KEY);
return this.tokenState || getAuthCache<string>(TOKEN_KEY);
}
get getRoleListState(): RoleEnum[] {
return this.roleListState.length > 0 ? this.roleListState : getCache<RoleEnum[]>(ROLES_KEY);
return this.roleListState.length > 0 ? this.roleListState : getAuthCache<RoleEnum[]>(ROLES_KEY);
}
@Mutation
......@@ -74,19 +59,19 @@ class User extends VuexModule {
@Mutation
commitUserInfoState(info: UserInfo): void {
this.userInfoState = info;
setCache(USER_INFO_KEY, info);
setAuthCache(USER_INFO_KEY, info);
}
@Mutation
commitRoleListState(roleList: RoleEnum[]): void {
this.roleListState = roleList;
setCache(ROLES_KEY, roleList);
setAuthCache(ROLES_KEY, roleList);
}
@Mutation
commitTokenState(info: string): void {
this.tokenState = info;
setCache(TOKEN_KEY, info);
setAuthCache(TOKEN_KEY, info);
}
/**
......
export interface LockInfo {
pwd: string | undefined;
isLock: boolean;
}
export interface UserInfo {
// 用户id
userId: string | number;
// 用户名
username: string;
// 真实名字
realName: string;
// 介绍
desc?: string;
}
import { Persistent, BasicKeys } from '/@/utils/cache/persistent';
import { CacheTypeEnum } from '/@/enums/cacheEnum';
import projectSetting from '/@/settings/projectSetting';
import { TOKEN_KEY } from '/@/enums/cacheEnum';
const { permissionCacheType } = projectSetting;
const isLocal = permissionCacheType === CacheTypeEnum.LOCAL;
export function getToken() {
return getAuthCache(TOKEN_KEY);
}
export function getAuthCache<T>(key: BasicKeys) {
const fn = isLocal ? Persistent.getLocal : Persistent.getSession;
return fn(key) as T;
}
export function setAuthCache(key: BasicKeys, value) {
const fn = isLocal ? Persistent.setLocal : Persistent.setSession;
return fn(key, value);
}
import type { UserInfo } from '/@/store/modules/user';
import type { LockInfo } from '/@/store/modules/lock';
import type { LockInfo, UserInfo } from '/@/store/types';
import { ProjectConfig } from '/#/config';
import { createLocalStorage, createSessionStorage } from '/@/utils/cache';
......
import type { GlobEnvConfig } from '/#/config';
import { useGlobSetting } from '/@/hooks/setting';
import { warn } from '/@/utils/log';
import pkg from '../../package.json';
import { getConfigFileName } from '../../build/getConfigFileName';
export function getCommonStoragePrefix() {
const globSetting = useGlobSetting();
return `${globSetting.shortName}__${getEnv()}`.toUpperCase();
const { VITE_GLOB_APP_SHORT_NAME } = getAppEnvConfig();
return `${VITE_GLOB_APP_SHORT_NAME}__${getEnv()}`.toUpperCase();
}
// Generate cache key according to version
......@@ -21,7 +21,27 @@ export function getAppEnvConfig() {
? // Get the global configuration (the configuration will be extracted independently when packaging)
((import.meta.env as unknown) as GlobEnvConfig)
: window[ENV_NAME as any]) as unknown) as GlobEnvConfig;
return ENV;
const {
VITE_GLOB_APP_TITLE,
VITE_GLOB_API_URL,
VITE_GLOB_APP_SHORT_NAME,
VITE_GLOB_API_URL_PREFIX,
VITE_GLOB_UPLOAD_URL,
} = ENV;
if (!/[a-zA-Z\_]*/.test(VITE_GLOB_APP_SHORT_NAME)) {
warn(
`VITE_GLOB_APP_SHORT_NAME Variables can only be characters/underscores, please modify in the environment variables and re-running.`
);
}
return {
VITE_GLOB_APP_TITLE,
VITE_GLOB_API_URL,
VITE_GLOB_APP_SHORT_NAME,
VITE_GLOB_API_URL_PREFIX,
VITE_GLOB_UPLOAD_URL,
};
}
/**
......
......@@ -4,6 +4,12 @@
import type { AxiosRequestConfig, AxiosResponse } from 'axios';
import type { RequestOptions, Result } from './types';
export interface CreateAxiosOptions extends AxiosRequestConfig {
prefixUrl?: string;
transform?: AxiosTransform;
requestOptions?: RequestOptions;
}
export abstract class AxiosTransform {
/**
* @description: Process configuration before request
......
import { useMessage } from '/@/hooks/web/useMessage';
import { userStore } from '/@/store/modules/user';
import { useI18n } from '/@/hooks/web/useI18n';
import router from '/@/router';
import { PageEnum } from '/@/enums/pageEnum';
const { createMessage } = useMessage();
const error = createMessage.error!;
......@@ -15,7 +17,7 @@ export function checkStatus(status: number, msg: string): void {
// Return to the current page after successful login. This step needs to be operated on the login page.
case 401:
error(t('sys.api.errMsg401'));
userStore.logout(true);
router.push(PageEnum.BASE_LOGIN);
break;
case 403:
error(t('sys.api.errMsg403'));
......
......@@ -2,10 +2,10 @@
// The axios configuration can be changed according to the project, just change the file, other files can be left unchanged
import type { AxiosResponse } from 'axios';
import type { CreateAxiosOptions, RequestOptions, Result } from './types';
import { VAxios } from './Axios';
import { AxiosTransform } from './axiosTransform';
import type { RequestOptions, Result } from './types';
import type { AxiosTransform, CreateAxiosOptions } from './axiosTransform';
import { VAxios } from './Axios';
import { checkStatus } from './checkStatus';
import { useGlobSetting } from '/@/hooks/setting';
......@@ -14,12 +14,12 @@ import { useMessage } from '/@/hooks/web/useMessage';
import { RequestEnum, ResultEnum, ContentTypeEnum } from '/@/enums/httpEnum';
import { isString } from '/@/utils/is';
import { getToken } from '/@/utils/auth';
import { setObjToUrlParams, deepMerge } from '/@/utils';
import { errorStore } from '/@/store/modules/error';
import { errorResult } from './const';
import { useI18n } from '/@/hooks/web/useI18n';
import { createNow, formatRequestDate } from './helper';
import { userStore } from '/@/store/modules/user';
const globSetting = useGlobSetting();
const prefix = globSetting.urlPrefix;
......@@ -137,7 +137,7 @@ const transform: AxiosTransform = {
*/
requestInterceptors: (config) => {
// 请求之前处理config
const token = userStore.getTokenState;
const token = getToken();
if (token) {
// jwt token
config.headers.Authorization = token;
......
import type { AxiosRequestConfig } from 'axios';
import type { AxiosTransform } from './axiosTransform';
export type ErrorMessageMode = 'none' | 'modal' | 'message' | undefined;
export interface RequestOptions {
......@@ -20,12 +18,6 @@ export interface RequestOptions {
ignoreCancelToken?: boolean;
}
export interface CreateAxiosOptions extends AxiosRequestConfig {
prefixUrl?: string;
transform?: AxiosTransform;
requestOptions?: RequestOptions;
}
export interface Result<T = any> {
code: number;
type: 'success' | 'error' | 'warning';
......
......@@ -3,7 +3,7 @@
<DeptTree class="w-1/4 xl:w-1/5" @select="handleSelect" />
<BasicTable @register="registerTable" class="w-3/4 xl:w-4/5">
<template #toolbar>
<a-button type="primary" @click="handleCreate"> 新增账号 </a-button>
<a-button type="primary" @click="handleCreate">新增账号</a-button>
</template>
<template #action="{ record }">
<TableAction
......
......@@ -47,7 +47,7 @@
class="enter-x"
size="large"
block
@click="handleReset"
@click="handleRegister"
:loading="loading"
>
{{ t('sys.login.registerButton') }}
......@@ -103,7 +103,7 @@
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.REGISTER);
async function handleReset() {
async function handleRegister() {
const data = await validForm();
if (!data) return;
console.log(data);
......@@ -114,7 +114,7 @@
formRef,
formData,
getFormRules,
handleReset,
handleRegister,
loading,
handleBackLogin,
getShow,
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论