mirror of
https://github.com/KwiTsukasa/kt-template-admin.git
synced 2026-05-27 16:35:47 +08:00
fix: 修复 Admin tsconfig 类型校验
This commit is contained in:
parent
51464d85d5
commit
c82ffa2b6c
@ -100,6 +100,16 @@ const PreviewGroup = defineAsyncComponent(() =>
|
|||||||
import('antdv-next/dist/image/index').then((res) => res.ImagePreviewGroup),
|
import('antdv-next/dist/image/index').then((res) => res.ImagePreviewGroup),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
type CropperExpose = {
|
||||||
|
getCropImage: (
|
||||||
|
format?: 'image/jpeg' | 'image/png',
|
||||||
|
quality?: number,
|
||||||
|
outputType?: 'base64' | 'blob',
|
||||||
|
targetWidth?: number,
|
||||||
|
targetHeight?: number,
|
||||||
|
) => Promise<Blob | string | undefined>;
|
||||||
|
};
|
||||||
|
|
||||||
const withDefaultPlaceholder = <T extends Component>(
|
const withDefaultPlaceholder = <T extends Component>(
|
||||||
component: T,
|
component: T,
|
||||||
type: 'input' | 'select',
|
type: 'input' | 'select',
|
||||||
@ -293,7 +303,7 @@ const withPreviewUpload = () => {
|
|||||||
let objectUrl: null | string = null;
|
let objectUrl: null | string = null;
|
||||||
|
|
||||||
const open = ref<boolean>(true);
|
const open = ref<boolean>(true);
|
||||||
const cropperRef = ref<InstanceType<typeof VCropper> | null>(null);
|
const cropperRef = ref<CropperExpose | null>(null);
|
||||||
|
|
||||||
const closeModal = () => {
|
const closeModal = () => {
|
||||||
open.value = false;
|
open.value = false;
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
"$schema": "https://json.schemastore.org/tsconfig",
|
"$schema": "https://json.schemastore.org/tsconfig",
|
||||||
"extends": "@vben/tsconfig/web-app.json",
|
"extends": "@vben/tsconfig/web-app.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
|
||||||
"paths": {
|
"paths": {
|
||||||
"#/*": ["./src/*"]
|
"#/*": ["./src/*"]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { defineConfig } from '@vben/vite-config';
|
import { defineConfig } from '@vben/vite-config';
|
||||||
|
|
||||||
export default defineConfig(async () => {
|
const config = defineConfig(async () => {
|
||||||
return {
|
return {
|
||||||
application: {},
|
application: {},
|
||||||
vite: {
|
vite: {
|
||||||
@ -17,4 +17,6 @@ export default defineConfig(async () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
}) as unknown;
|
||||||
|
|
||||||
|
export default config;
|
||||||
|
|||||||
@ -8,7 +8,6 @@
|
|||||||
"moduleDetection": "force",
|
"moduleDetection": "force",
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
|
|
||||||
"baseUrl": ".",
|
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
|
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"composite": false,
|
"composite": false,
|
||||||
"lib": ["ESNext"],
|
"lib": ["ESNext"],
|
||||||
"baseUrl": "./",
|
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"types": ["node"],
|
"types": ["node"],
|
||||||
"noImplicitAny": true
|
"noImplicitAny": true
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
"base.json",
|
"base.json",
|
||||||
"library.json",
|
"library.json",
|
||||||
"node.json",
|
"node.json",
|
||||||
|
"types",
|
||||||
"web-app.json",
|
"web-app.json",
|
||||||
"web.json"
|
"web.json"
|
||||||
],
|
],
|
||||||
|
|||||||
10
internal/tsconfig/types/vben-web/index.d.ts
vendored
Normal file
10
internal/tsconfig/types/vben-web/index.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
declare module '*.vue' {
|
||||||
|
const component: import('vue').DefineComponent<
|
||||||
|
Record<string, unknown>,
|
||||||
|
Record<string, unknown>,
|
||||||
|
Record<string, unknown>
|
||||||
|
>;
|
||||||
|
export default component;
|
||||||
|
}
|
||||||
@ -3,6 +3,6 @@
|
|||||||
"display": "Web Application",
|
"display": "Web Application",
|
||||||
"extends": "./web.json",
|
"extends": "./web.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"types": ["vite/client", "@vben/types/global"]
|
"types": ["@vben/tsconfig/types/vben-web", "@vben/types/global"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"types": ["vite/client"],
|
"types": ["@vben/tsconfig/types/vben-web"],
|
||||||
"declaration": false
|
"declaration": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,7 +35,8 @@ async function loadConditionPlugins(conditionPlugins: ConditionPlugin[]) {
|
|||||||
const plugins: PluginOption[] = [];
|
const plugins: PluginOption[] = [];
|
||||||
for (const conditionPlugin of conditionPlugins) {
|
for (const conditionPlugin of conditionPlugins) {
|
||||||
if (conditionPlugin.condition) {
|
if (conditionPlugin.condition) {
|
||||||
const realPlugins = await conditionPlugin.plugins();
|
// 第三方插件可能绑定到不同的 Vite 类型实例,运行时统一收敛为 Vite PluginOption。
|
||||||
|
const realPlugins = (await conditionPlugin.plugins()) as PluginOption[];
|
||||||
plugins.push(...realPlugins);
|
plugins.push(...realPlugins);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ async function viteVxeTableImportsPlugin(): Promise<PluginOption> {
|
|||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
];
|
] as unknown as PluginOption;
|
||||||
}
|
}
|
||||||
|
|
||||||
export { viteVxeTableImportsPlugin };
|
export { viteVxeTableImportsPlugin };
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import type { PluginVisualizerOptions } from 'rollup-plugin-visualizer';
|
import type { PluginVisualizerOptions } from 'rollup-plugin-visualizer';
|
||||||
import type {
|
import type {
|
||||||
ConfigEnv,
|
ConfigEnv,
|
||||||
PluginOption,
|
|
||||||
UserConfig,
|
UserConfig,
|
||||||
UserConfigFnPromise,
|
UserConfigFnPromise,
|
||||||
} from 'vite';
|
} from 'vite';
|
||||||
@ -138,7 +137,7 @@ interface ConditionPlugin {
|
|||||||
* 插件对象
|
* 插件对象
|
||||||
* @description 返回插件数组或 Promise
|
* @description 返回插件数组或 Promise
|
||||||
*/
|
*/
|
||||||
plugins: () => PluginOption[] | PromiseLike<PluginOption[]>;
|
plugins: () => PromiseLike<unknown[]> | unknown[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { FormApi } from '../src/form-api';
|
|||||||
|
|
||||||
describe('formApi', () => {
|
describe('formApi', () => {
|
||||||
let formApi: FormApi;
|
let formApi: FormApi;
|
||||||
|
const componentRefMap = () => new Map<string, unknown>();
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
formApi = new FormApi();
|
formApi = new FormApi();
|
||||||
@ -41,7 +42,7 @@ describe('formApi', () => {
|
|||||||
values: { name: 'test' },
|
values: { name: 'test' },
|
||||||
};
|
};
|
||||||
|
|
||||||
await formApi.mount(formActions);
|
formApi.mount(formActions, componentRefMap());
|
||||||
expect(formApi.isMounted).toBe(true);
|
expect(formApi.isMounted).toBe(true);
|
||||||
expect(formApi.form).toEqual(formActions);
|
expect(formApi.form).toEqual(formActions);
|
||||||
});
|
});
|
||||||
@ -52,7 +53,7 @@ describe('formApi', () => {
|
|||||||
values: { name: 'test' },
|
values: { name: 'test' },
|
||||||
};
|
};
|
||||||
|
|
||||||
await formApi.mount(formActions);
|
formApi.mount(formActions, componentRefMap());
|
||||||
const values = await formApi.getValues();
|
const values = await formApi.getValues();
|
||||||
expect(values).toEqual({ name: 'test' });
|
expect(values).toEqual({ name: 'test' });
|
||||||
});
|
});
|
||||||
@ -65,7 +66,7 @@ describe('formApi', () => {
|
|||||||
values: { name: 'test' },
|
values: { name: 'test' },
|
||||||
};
|
};
|
||||||
|
|
||||||
await formApi.mount(formActions);
|
formApi.mount(formActions, componentRefMap());
|
||||||
await formApi.setFieldValue('name', 'new value');
|
await formApi.setFieldValue('name', 'new value');
|
||||||
expect(setFieldValueMock).toHaveBeenCalledWith(
|
expect(setFieldValueMock).toHaveBeenCalledWith(
|
||||||
'name',
|
'name',
|
||||||
@ -82,7 +83,7 @@ describe('formApi', () => {
|
|||||||
values: { name: 'test' },
|
values: { name: 'test' },
|
||||||
};
|
};
|
||||||
|
|
||||||
await formApi.mount(formActions);
|
formApi.mount(formActions, componentRefMap());
|
||||||
await formApi.resetForm();
|
await formApi.resetForm();
|
||||||
expect(resetFormMock).toHaveBeenCalled();
|
expect(resetFormMock).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
@ -100,7 +101,7 @@ describe('formApi', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
formApi.setState(state);
|
formApi.setState(state);
|
||||||
await formApi.mount(formActions);
|
formApi.mount(formActions, componentRefMap());
|
||||||
|
|
||||||
const result = await formApi.submitForm();
|
const result = await formApi.submitForm();
|
||||||
expect(formActions.submitForm).toHaveBeenCalled();
|
expect(formActions.submitForm).toHaveBeenCalled();
|
||||||
@ -120,7 +121,7 @@ describe('formApi', () => {
|
|||||||
validate: validateMock,
|
validate: validateMock,
|
||||||
};
|
};
|
||||||
|
|
||||||
await formApi.mount(formActions);
|
formApi.mount(formActions, componentRefMap());
|
||||||
const isValid = await formApi.validate();
|
const isValid = await formApi.validate();
|
||||||
expect(validateMock).toHaveBeenCalled();
|
expect(validateMock).toHaveBeenCalled();
|
||||||
expect(isValid).toBe(true);
|
expect(isValid).toBe(true);
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
"$schema": "https://json.schemastore.org/tsconfig",
|
"$schema": "https://json.schemastore.org/tsconfig",
|
||||||
"extends": "@vben/tsconfig/web.json",
|
"extends": "@vben/tsconfig/web.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
|
||||||
"paths": {
|
"paths": {
|
||||||
"@vben-core/shadcn-ui/*": ["./src/*"]
|
"@vben-core/shadcn-ui/*": ["./src/*"]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
import type { TabsProps } from './types';
|
import type { TabsProps } from './types';
|
||||||
|
import type { ComponentPublicInstance } from 'vue';
|
||||||
|
|
||||||
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
|
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
|
||||||
|
|
||||||
import { VbenScrollbar } from '@vben-core/shadcn-ui';
|
|
||||||
|
|
||||||
import { useDebounceFn } from '@vueuse/core';
|
import { useDebounceFn } from '@vueuse/core';
|
||||||
|
|
||||||
type DomElement = Element | null | undefined;
|
type DomElement = Element | null | undefined;
|
||||||
@ -12,7 +11,7 @@ export function useTabsViewScroll(props: TabsProps) {
|
|||||||
let resizeObserver: null | ResizeObserver = null;
|
let resizeObserver: null | ResizeObserver = null;
|
||||||
let mutationObserver: MutationObserver | null = null;
|
let mutationObserver: MutationObserver | null = null;
|
||||||
let tabItemCount = 0;
|
let tabItemCount = 0;
|
||||||
const scrollbarRef = ref<InstanceType<typeof VbenScrollbar> | null>(null);
|
const scrollbarRef = ref<ComponentPublicInstance | null>(null);
|
||||||
const scrollViewportEl = ref<DomElement>(null);
|
const scrollViewportEl = ref<DomElement>(null);
|
||||||
const showScrollButton = ref(false);
|
const showScrollButton = ref(false);
|
||||||
const scrollIsAtLeft = ref(true);
|
const scrollIsAtLeft = ref(true);
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import type { AxiosResponse } from 'axios';
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import MockAdapter from 'axios-mock-adapter';
|
import MockAdapter from 'axios-mock-adapter';
|
||||||
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
||||||
@ -92,7 +94,8 @@ describe('requestClient', () => {
|
|||||||
|
|
||||||
mock.onGet('/test/download').reply(200, mockFileContent);
|
mock.onGet('/test/download').reply(200, mockFileContent);
|
||||||
|
|
||||||
const res = await requestClient.download('/test/download');
|
const res =
|
||||||
|
await requestClient.download<AxiosResponse<Blob>>('/test/download');
|
||||||
|
|
||||||
expect(res.data).toBeInstanceOf(Blob);
|
expect(res.data).toBeInstanceOf(Blob);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -38,15 +38,15 @@ const mockRoutes = [
|
|||||||
|
|
||||||
describe('hasAuthority', () => {
|
describe('hasAuthority', () => {
|
||||||
it('should return true if there is no authority defined', () => {
|
it('should return true if there is no authority defined', () => {
|
||||||
expect(hasAuthority(mockRoutes[2], ['admin'])).toBe(true);
|
expect(hasAuthority(mockRoutes[2]!, ['admin'])).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true if the user has the required authority', () => {
|
it('should return true if the user has the required authority', () => {
|
||||||
expect(hasAuthority(mockRoutes[0], ['admin'])).toBe(true);
|
expect(hasAuthority(mockRoutes[0]!, ['admin'])).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false if the user does not have the required authority', () => {
|
it('should return false if the user does not have the required authority', () => {
|
||||||
expect(hasAuthority(mockRoutes[1], ['user'])).toBe(false);
|
expect(hasAuthority(mockRoutes[1]!, ['user'])).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -27,12 +27,8 @@ function generateMenus(
|
|||||||
// 获取最终的路由路径
|
// 获取最终的路由路径
|
||||||
const path = finalRoutesMap[route.name as string] ?? route.path ?? '';
|
const path = finalRoutesMap[route.name as string] ?? route.path ?? '';
|
||||||
|
|
||||||
const {
|
const { name: routeName, redirect, children = [] } = route;
|
||||||
meta = {} as RouteMeta,
|
const meta = (route.meta ?? {}) as unknown as Partial<RouteMeta>;
|
||||||
name: routeName,
|
|
||||||
redirect,
|
|
||||||
children = [],
|
|
||||||
} = route;
|
|
||||||
const {
|
const {
|
||||||
activeIcon,
|
activeIcon,
|
||||||
badge,
|
badge,
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import type { RouteRecordRaw } from 'vue-router';
|
import type { RouteRecordRaw } from 'vue-router';
|
||||||
|
|
||||||
|
import type { RouteMeta } from '@vben-core/typings';
|
||||||
|
|
||||||
import { filterTree, mapTree } from '@vben-core/shared/utils';
|
import { filterTree, mapTree } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,7 +36,8 @@ async function generateRoutesByFrontend(
|
|||||||
* @param access
|
* @param access
|
||||||
*/
|
*/
|
||||||
function hasAuthority(route: RouteRecordRaw, access: string[]) {
|
function hasAuthority(route: RouteRecordRaw, access: string[]) {
|
||||||
const authority = route.meta?.authority;
|
const meta = route.meta as Partial<RouteMeta> | undefined;
|
||||||
|
const authority = meta?.authority;
|
||||||
if (!authority) {
|
if (!authority) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -48,10 +51,12 @@ function hasAuthority(route: RouteRecordRaw, access: string[]) {
|
|||||||
* @param route
|
* @param route
|
||||||
*/
|
*/
|
||||||
function menuHasVisibleWithForbidden(route: RouteRecordRaw) {
|
function menuHasVisibleWithForbidden(route: RouteRecordRaw) {
|
||||||
|
const meta = route.meta as Partial<RouteMeta> | undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
!!route.meta?.authority &&
|
!!meta?.authority &&
|
||||||
Reflect.has(route.meta || {}, 'menuVisibleWithForbidden') &&
|
Reflect.has(meta || {}, 'menuVisibleWithForbidden') &&
|
||||||
!!route.meta?.menuVisibleWithForbidden
|
!!meta?.menuVisibleWithForbidden
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user