mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-26 00:26:20 +08:00
wip: support vite
This commit is contained in:
@@ -23,5 +23,5 @@ VITE_GLOB_API_URL_PREFIX=
|
||||
# use pwa
|
||||
VITE_USE_PWA = false
|
||||
|
||||
# TODO use Cdn
|
||||
VITE_USE_CDN = true
|
||||
# Is it compatible with older browsers
|
||||
VITE_LEGACY = false
|
||||
|
@@ -1,26 +0,0 @@
|
||||
// #!/usr/bin/env node
|
||||
|
||||
import { sh } from 'tasksfile';
|
||||
import { errorConsole, successConsole } from '../utils';
|
||||
|
||||
export const runChangeLog = async () => {
|
||||
try {
|
||||
let cmd = `conventional-changelog -p custom-config -i CHANGELOG.md -s -r 0 `;
|
||||
|
||||
await sh(cmd, {
|
||||
async: true,
|
||||
nopipe: true,
|
||||
});
|
||||
await sh('prettier --write **/CHANGELOG.md ', {
|
||||
async: true,
|
||||
nopipe: true,
|
||||
});
|
||||
successConsole('CHANGE_LOG.md generated successfully!');
|
||||
} catch (error) {
|
||||
errorConsole('CHANGE_LOG.md generated error\n' + error);
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
runChangeLog();
|
@@ -3,7 +3,6 @@
|
||||
import { argv } from 'yargs';
|
||||
import { runBuildConfig } from './buildConf';
|
||||
import { errorConsole, successConsole } from '../utils';
|
||||
import { startGzipStyle } from '../vite/plugin/gzip/compress';
|
||||
|
||||
export const runBuild = async () => {
|
||||
try {
|
||||
@@ -13,8 +12,6 @@ export const runBuild = async () => {
|
||||
if (!argvList.includes('no-conf')) {
|
||||
await runBuildConfig();
|
||||
}
|
||||
// await runUpdateHtml();
|
||||
await startGzipStyle();
|
||||
successConsole('Vite Build successfully!');
|
||||
} catch (error) {
|
||||
errorConsole('Vite Build Error\n' + error);
|
||||
|
@@ -63,11 +63,11 @@ export function getIPAddress() {
|
||||
return '';
|
||||
}
|
||||
|
||||
export function isDevFn(mode: 'development' | 'production'): boolean {
|
||||
export function isDevFn(mode: string): boolean {
|
||||
return mode === 'development';
|
||||
}
|
||||
|
||||
export function isProdFn(mode: 'development' | 'production'): boolean {
|
||||
export function isProdFn(mode: string): boolean {
|
||||
return mode === 'production';
|
||||
}
|
||||
|
||||
@@ -85,13 +85,6 @@ export function isBuildGzip(): boolean {
|
||||
return process.env.VITE_BUILD_GZIP === 'true';
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to generate package site
|
||||
*/
|
||||
export function isSiteMode(): boolean {
|
||||
return process.env.SITE === 'true';
|
||||
}
|
||||
|
||||
export interface ViteEnv {
|
||||
VITE_PORT: number;
|
||||
VITE_USE_MOCK: boolean;
|
||||
@@ -99,10 +92,12 @@ export interface ViteEnv {
|
||||
VITE_PUBLIC_PATH: string;
|
||||
VITE_PROXY: [string, string][];
|
||||
VITE_GLOB_APP_TITLE: string;
|
||||
VITE_GLOB_APP_SHORT_NAME: string;
|
||||
VITE_USE_CDN: boolean;
|
||||
VITE_DROP_CONSOLE: boolean;
|
||||
VITE_BUILD_GZIP: boolean;
|
||||
VITE_DYNAMIC_IMPORT: boolean;
|
||||
VITE_LEGACY: boolean;
|
||||
}
|
||||
|
||||
// Read all environment variable configuration files to process.env
|
||||
|
@@ -1,12 +0,0 @@
|
||||
// Baidu statistics code for site deployment
|
||||
// Only open in build:site
|
||||
export const hmScript = `<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?384d6046e02f6ac4ea075357bd0e9b43";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
`;
|
12
build/vite/plugin/gzip.ts
Normal file
12
build/vite/plugin/gzip.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import gzipPlugin from 'rollup-plugin-gzip';
|
||||
import { isBuildGzip } from '../../utils';
|
||||
import { Plugin } from 'vite';
|
||||
export function configGzipPlugin(isBuild: boolean): Plugin | Plugin[] {
|
||||
const useGzip = isBuild && isBuildGzip;
|
||||
|
||||
if (useGzip) {
|
||||
return gzipPlugin();
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
import { gzip } from 'zlib';
|
||||
import { readFileSync, writeFileSync } from 'fs';
|
||||
import { GzipPluginOptions } from './types';
|
||||
import { readAllFile, getCwdPath, isBuildGzip, isSiteMode } from '../../../utils';
|
||||
|
||||
export function startGzip(
|
||||
fileContent: string | Buffer,
|
||||
options: GzipPluginOptions = {}
|
||||
): Promise<Buffer> {
|
||||
return new Promise((resolve, reject) => {
|
||||
gzip(fileContent, options.gzipOptions || {}, (err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 手动压缩css
|
||||
export async function startGzipStyle() {
|
||||
if (isBuildGzip() || isSiteMode()) {
|
||||
const outDir = 'dist';
|
||||
const assets = '_assets';
|
||||
const allCssFile = readAllFile(getCwdPath(outDir, assets), /\.(css)$/);
|
||||
for (const path of allCssFile) {
|
||||
const source = readFileSync(path);
|
||||
const content = await startGzip(source);
|
||||
const ds = path.split('/');
|
||||
const fileName = ds[ds.length - 1];
|
||||
writeFileSync(getCwdPath(outDir, assets, `${fileName}.gz`), content);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,196 +0,0 @@
|
||||
// 修改自https://github.com/kryops/rollup-plugin-gzip
|
||||
// 因为rollup-plugin-gzip不支持vite
|
||||
// vite对css打包独立的。所以不能在打包的时候顺带打包css
|
||||
// TODO rc.9会支持 configurBuild 配置项。到时候重新修改
|
||||
|
||||
import { readFile, writeFile } from 'fs';
|
||||
import { basename } from 'path';
|
||||
import { promisify } from 'util';
|
||||
import { gzip } from 'zlib';
|
||||
|
||||
import { OutputAsset, OutputChunk, OutputOptions, Plugin } from 'rollup';
|
||||
import { GzipPluginOptions } from './types';
|
||||
|
||||
const isFunction = (arg: unknown): arg is (...args: any[]) => any => typeof arg === 'function';
|
||||
const isRegExp = (arg: unknown): arg is RegExp =>
|
||||
Object.prototype.toString.call(arg) === '[object RegExp]';
|
||||
|
||||
export type StringMappingOption = (originalString: string) => string;
|
||||
export type CustomCompressionOption = (
|
||||
content: string | Buffer
|
||||
) => string | Buffer | Promise<string | Buffer>;
|
||||
|
||||
const readFilePromise = promisify(readFile);
|
||||
const writeFilePromise = promisify(writeFile);
|
||||
|
||||
// functionality partially copied from rollup
|
||||
|
||||
/**
|
||||
* copied from https://github.com/rollup/rollup/blob/master/src/rollup/index.ts#L450
|
||||
*/
|
||||
function isOutputChunk(file: OutputAsset | OutputChunk): file is OutputChunk {
|
||||
return typeof (file as OutputChunk).code === 'string';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string/buffer content from a file object.
|
||||
* Important for adding source map comments
|
||||
*
|
||||
* Copied partially from rollup.writeOutputFile
|
||||
* https://github.com/rollup/rollup/blob/master/src/rollup/index.ts#L454
|
||||
*/
|
||||
function getOutputFileContent(
|
||||
outputFileName: string,
|
||||
outputFile: OutputAsset | OutputChunk,
|
||||
outputOptions: OutputOptions
|
||||
): string | Buffer {
|
||||
if (isOutputChunk(outputFile)) {
|
||||
let source: string | Buffer;
|
||||
source = outputFile.code;
|
||||
if (outputOptions.sourcemap && outputFile.map) {
|
||||
const url =
|
||||
outputOptions.sourcemap === 'inline'
|
||||
? outputFile.map.toUrl()
|
||||
: `${basename(outputFileName)}.map`;
|
||||
|
||||
// https://github.com/rollup/rollup/blob/master/src/utils/sourceMappingURL.ts#L1
|
||||
source += `//# source` + `MappingURL=${url}\n`;
|
||||
}
|
||||
return source;
|
||||
} else {
|
||||
return typeof outputFile.source === 'string'
|
||||
? outputFile.source
|
||||
: // just to be sure, as it is typed string | Uint8Array in rollup 2.0.0
|
||||
Buffer.from(outputFile.source);
|
||||
}
|
||||
}
|
||||
|
||||
// actual plugin code
|
||||
|
||||
function gzipPlugin(options: GzipPluginOptions = {}): Plugin {
|
||||
// check for old options
|
||||
if ('algorithm' in options) {
|
||||
console.warn(
|
||||
'[rollup-plugin-gzip] The "algorithm" option is not supported any more! ' +
|
||||
'Use "customCompression" instead to specify a different compression algorithm.'
|
||||
);
|
||||
}
|
||||
if ('options' in options) {
|
||||
console.warn('[rollup-plugin-gzip] The "options" option was renamed to "gzipOptions"!');
|
||||
}
|
||||
if ('additional' in options) {
|
||||
console.warn('[rollup-plugin-gzip] The "additional" option was renamed to "additionalFiles"!');
|
||||
}
|
||||
if ('delay' in options) {
|
||||
console.warn('[rollup-plugin-gzip] The "delay" option was renamed to "additionalFilesDelay"!');
|
||||
}
|
||||
|
||||
const compressGzip: CustomCompressionOption = (fileContent) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
gzip(fileContent, options.gzipOptions || {}, (err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const doCompress = options.customCompression || compressGzip;
|
||||
|
||||
const mapFileName: StringMappingOption = isFunction(options.fileName)
|
||||
? (options.fileName as StringMappingOption)
|
||||
: (fileName: string) => fileName + (options.fileName || '.gz');
|
||||
|
||||
const plugin: Plugin = {
|
||||
name: 'gzip',
|
||||
|
||||
generateBundle(outputOptions, bundle) {
|
||||
return Promise.all(
|
||||
Object.keys(bundle)
|
||||
.map((fileName) => {
|
||||
const fileEntry = bundle[fileName];
|
||||
|
||||
// file name filter option check
|
||||
|
||||
const fileNameFilter = options.filter || /\.(js|mjs|json|css|html)$/;
|
||||
|
||||
if (isRegExp(fileNameFilter) && !fileName.match(fileNameFilter)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (
|
||||
isFunction(fileNameFilter) &&
|
||||
!(fileNameFilter as (x: string) => boolean)(fileName)
|
||||
) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const fileContent = getOutputFileContent(fileName, fileEntry, outputOptions);
|
||||
|
||||
// minSize option check
|
||||
if (options.minSize && options.minSize > fileContent.length) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.resolve(doCompress(fileContent))
|
||||
.then((compressedContent) => {
|
||||
const compressedFileName = mapFileName(fileName);
|
||||
bundle[compressedFileName] = {
|
||||
type: 'asset', // Rollup >= 1.21
|
||||
name: compressedFileName,
|
||||
fileName: compressedFileName,
|
||||
isAsset: true, // Rollup < 1.21
|
||||
source: compressedContent,
|
||||
};
|
||||
})
|
||||
.catch((err: any) => {
|
||||
console.error(err);
|
||||
return Promise.reject('[rollup-plugin-gzip] Error compressing file ' + fileName);
|
||||
});
|
||||
})
|
||||
.concat([
|
||||
(() => {
|
||||
if (!options.additionalFiles || !options.additionalFiles.length)
|
||||
return Promise.resolve();
|
||||
|
||||
const compressAdditionalFiles = () =>
|
||||
Promise.all(
|
||||
options.additionalFiles!.map((filePath) =>
|
||||
readFilePromise(filePath)
|
||||
.then((fileContent) => doCompress(fileContent))
|
||||
.then((compressedContent) => {
|
||||
return writeFilePromise(mapFileName(filePath), compressedContent);
|
||||
})
|
||||
.catch(() => {
|
||||
return Promise.reject(
|
||||
'[rollup-plugin-gzip] Error compressing additional file ' +
|
||||
filePath +
|
||||
'. Please check the spelling of your configured additionalFiles. ' +
|
||||
'You might also have to increase the value of the additionalFilesDelay option.'
|
||||
);
|
||||
})
|
||||
)
|
||||
) as Promise<any>;
|
||||
|
||||
// additional files can be processed outside of rollup after a delay
|
||||
// for older plugins or plugins that write to disk (curcumventing rollup) without awaiting
|
||||
const additionalFilesDelay = options.additionalFilesDelay || 0;
|
||||
|
||||
if (additionalFilesDelay) {
|
||||
setTimeout(compressAdditionalFiles, additionalFilesDelay);
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return compressAdditionalFiles();
|
||||
}
|
||||
})(),
|
||||
])
|
||||
) as Promise<any>;
|
||||
},
|
||||
};
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
export default gzipPlugin;
|
@@ -1,56 +0,0 @@
|
||||
import type { ZlibOptions } from 'zlib';
|
||||
|
||||
export type StringMappingOption = (originalString: string) => string;
|
||||
export type CustomCompressionOption = (
|
||||
content: string | Buffer
|
||||
) => string | Buffer | Promise<string | Buffer>;
|
||||
|
||||
export interface GzipPluginOptions {
|
||||
/**
|
||||
* Control which of the output files to compress
|
||||
*
|
||||
* Defaults to `/\.(js|mjs|json|css|html)$/`
|
||||
*/
|
||||
filter?: RegExp | ((fileName: string) => boolean);
|
||||
|
||||
/**
|
||||
* GZIP compression options, see https://nodejs.org/api/zlib.html#zlib_class_options
|
||||
*/
|
||||
gzipOptions?: ZlibOptions;
|
||||
|
||||
/**
|
||||
* Specified the minimum size in Bytes for a file to get compressed.
|
||||
* Files that are smaller than this threshold will not be compressed.
|
||||
* This does not apply to the files specified through `additionalFiles`!
|
||||
*/
|
||||
minSize?: number;
|
||||
|
||||
/**
|
||||
* This option allows you to compress additional files outside of the main rollup bundling process.
|
||||
* The processing is delayed to make sure the files are written on disk; the delay is controlled
|
||||
* through `additionalFilesDelay`.
|
||||
*/
|
||||
additionalFiles?: string[];
|
||||
|
||||
/**
|
||||
* This options sets a delay (ms) before the plugin compresses the files specified through `additionalFiles`.
|
||||
* Increase this value if your artifacts take a long time to generate.
|
||||
*
|
||||
* Defaults to `2000`
|
||||
*/
|
||||
additionalFilesDelay?: number;
|
||||
|
||||
/**
|
||||
* Set a custom compression algorithm. The function can either return the compressed contents synchronously,
|
||||
* or otherwise return a promise for asynchronous processing.
|
||||
*/
|
||||
customCompression?: CustomCompressionOption;
|
||||
|
||||
/**
|
||||
* Set a custom file name convention for the compressed files. Can be a suffix string or a function
|
||||
* returning the file name.
|
||||
*
|
||||
* Defaults to `.gz`
|
||||
*/
|
||||
fileName?: string | StringMappingOption;
|
||||
}
|
@@ -1,37 +1,32 @@
|
||||
import type { Plugin } from 'vite';
|
||||
import ViteHtmlPlugin from 'vite-plugin-html';
|
||||
import { isProdFn, isSiteMode, ViteEnv } from '../../utils';
|
||||
import html from 'vite-plugin-html';
|
||||
import { ViteEnv } from '../../utils';
|
||||
|
||||
import { hmScript } from '../hm';
|
||||
// @ts-ignore
|
||||
import pkg from '../../../package.json';
|
||||
import { GLOB_CONFIG_FILE_NAME } from '../../constant';
|
||||
|
||||
export function setupHtmlPlugin(
|
||||
plugins: Plugin[],
|
||||
env: ViteEnv,
|
||||
mode: 'development' | 'production'
|
||||
) {
|
||||
export function configHtmlPlugin(env: ViteEnv, isBuild: boolean) {
|
||||
const { VITE_GLOB_APP_TITLE, VITE_PUBLIC_PATH } = env;
|
||||
|
||||
const htmlPlugin = ViteHtmlPlugin({
|
||||
// html title
|
||||
title: VITE_GLOB_APP_TITLE,
|
||||
minify: isProdFn(mode),
|
||||
options: {
|
||||
publicPath: VITE_PUBLIC_PATH,
|
||||
// Package and insert additional configuration files
|
||||
injectConfig: isProdFn(mode)
|
||||
? `<script src='${VITE_PUBLIC_PATH || './'}${GLOB_CONFIG_FILE_NAME}?v=${
|
||||
pkg.version
|
||||
}-${new Date().getTime()}'></script>`
|
||||
: '',
|
||||
// Insert Baidu statistics code
|
||||
hmScript: isSiteMode() ? hmScript : '',
|
||||
title: VITE_GLOB_APP_TITLE,
|
||||
const htmlPlugin: Plugin[] = html({
|
||||
minify: isBuild,
|
||||
inject: {
|
||||
injectData: {
|
||||
title: VITE_GLOB_APP_TITLE,
|
||||
},
|
||||
tags: isBuild
|
||||
? [
|
||||
{
|
||||
tag: 'script',
|
||||
attrs: {
|
||||
src: `${VITE_PUBLIC_PATH || './'}${GLOB_CONFIG_FILE_NAME}?v=${
|
||||
pkg.version
|
||||
}-${new Date().getTime()}`,
|
||||
},
|
||||
},
|
||||
]
|
||||
: [],
|
||||
},
|
||||
});
|
||||
|
||||
plugins.push(htmlPlugin);
|
||||
return plugins;
|
||||
return htmlPlugin;
|
||||
}
|
||||
|
12
build/vite/plugin/importContext.ts
Normal file
12
build/vite/plugin/importContext.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import dynamicImport from 'vite-plugin-import-context';
|
||||
import type { ViteEnv } from '../../utils';
|
||||
import type { Plugin } from 'vite';
|
||||
|
||||
export function configDynamicImport(env: ViteEnv) {
|
||||
const { VITE_DYNAMIC_IMPORT } = env;
|
||||
const dynamicImportPlugin: Plugin = dynamicImport({
|
||||
include: ['**/*.ts'],
|
||||
autoImportRoute: VITE_DYNAMIC_IMPORT,
|
||||
});
|
||||
return dynamicImportPlugin;
|
||||
}
|
@@ -1,47 +1,44 @@
|
||||
import type { Plugin as VitePlugin } from 'vite';
|
||||
import type { Plugin as rollupPlugin } from 'rollup';
|
||||
import type { Plugin } from 'vite';
|
||||
|
||||
import PurgeIcons from 'vite-plugin-purge-icons';
|
||||
|
||||
import visualizer from 'rollup-plugin-visualizer';
|
||||
import gzipPlugin from './gzip/index';
|
||||
|
||||
// @ts-ignore
|
||||
import pkg from '../../../package.json';
|
||||
import { isSiteMode, ViteEnv, isReportMode, isBuildGzip } from '../../utils';
|
||||
import { setupHtmlPlugin } from './html';
|
||||
import { setupPwaPlugin } from './pwa';
|
||||
import { setupMockPlugin } from './mock';
|
||||
import { ViteEnv, isReportMode } from '../../utils';
|
||||
import { configHtmlPlugin } from './html';
|
||||
import { configPwaConfig } from './pwa';
|
||||
import { configMockPlugin } from './mock';
|
||||
import { configDynamicImport } from './importContext';
|
||||
import { configGzipPlugin } from './gzip';
|
||||
|
||||
// gen vite plugins
|
||||
export function createVitePlugins(viteEnv: ViteEnv, mode: 'development' | 'production') {
|
||||
const vitePlugins: VitePlugin[] = [];
|
||||
export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean, mode: string) {
|
||||
const vitePlugins: (Plugin | Plugin[])[] = [];
|
||||
|
||||
// vite-plugin-html
|
||||
setupHtmlPlugin(vitePlugins, viteEnv, mode);
|
||||
vitePlugins.push(configHtmlPlugin(viteEnv, isBuild));
|
||||
|
||||
// vite-plugin-pwa
|
||||
setupPwaPlugin(vitePlugins, viteEnv, mode);
|
||||
vitePlugins.push(configPwaConfig(viteEnv, isBuild));
|
||||
|
||||
// vite-plugin-mock
|
||||
setupMockPlugin(vitePlugins, viteEnv, mode);
|
||||
vitePlugins.push(configMockPlugin(viteEnv, isBuild));
|
||||
|
||||
// vite-plugin-import-context
|
||||
vitePlugins.push(configDynamicImport(viteEnv));
|
||||
|
||||
// vite-plugin-purge-icons
|
||||
vitePlugins.push(PurgeIcons());
|
||||
|
||||
// rollup-plugin-gzip
|
||||
vitePlugins.push(configGzipPlugin(isBuild));
|
||||
|
||||
// rollup-plugin-visualizer
|
||||
if (isReportMode()) {
|
||||
vitePlugins.push(visualizer({ filename: './build/.cache/stats.html', open: true }) as Plugin);
|
||||
}
|
||||
|
||||
return vitePlugins;
|
||||
}
|
||||
|
||||
// gen rollup plugins
|
||||
export function createRollupPlugin() {
|
||||
const rollupPlugins: rollupPlugin[] = [];
|
||||
|
||||
if (isReportMode()) {
|
||||
// rollup-plugin-visualizer
|
||||
rollupPlugins.push(visualizer({ filename: './build/.cache/stats.html', open: true }) as Plugin);
|
||||
}
|
||||
if (isBuildGzip() || isSiteMode()) {
|
||||
// rollup-plugin-gizp
|
||||
rollupPlugins.push(gzipPlugin());
|
||||
}
|
||||
|
||||
return rollupPlugins;
|
||||
}
|
||||
|
@@ -1,24 +1,19 @@
|
||||
import { createMockServer } from 'vite-plugin-mock';
|
||||
import type { Plugin } from 'vite';
|
||||
import { isDevFn, ViteEnv } from '../../utils';
|
||||
import { viteMockServe } from 'vite-plugin-mock';
|
||||
import { ViteEnv } from '../../utils';
|
||||
|
||||
export function setupMockPlugin(
|
||||
plugins: Plugin[],
|
||||
env: ViteEnv,
|
||||
mode: 'development' | 'production'
|
||||
) {
|
||||
export function configMockPlugin(env: ViteEnv, isBuild: boolean) {
|
||||
const { VITE_USE_MOCK } = env;
|
||||
|
||||
const useMock = isDevFn(mode) && VITE_USE_MOCK;
|
||||
const useMock = !isBuild && VITE_USE_MOCK;
|
||||
|
||||
if (useMock) {
|
||||
const mockPlugin = createMockServer({
|
||||
const mockPlugin = viteMockServe({
|
||||
ignore: /^\_/,
|
||||
mockPath: 'mock',
|
||||
showTime: true,
|
||||
localEnabled: useMock,
|
||||
});
|
||||
plugins.push(mockPlugin);
|
||||
return mockPlugin;
|
||||
}
|
||||
return plugins;
|
||||
return [];
|
||||
}
|
||||
|
@@ -1,35 +1,31 @@
|
||||
import { VitePWA } from 'vite-plugin-pwa';
|
||||
import type { Plugin } from 'vite';
|
||||
|
||||
import { ViteEnv } from '../../utils';
|
||||
|
||||
export function setupPwaPlugin(
|
||||
plugins: Plugin[],
|
||||
env: ViteEnv,
|
||||
// @ts-ignore
|
||||
mode: 'development' | 'production'
|
||||
) {
|
||||
const { VITE_USE_PWA } = env;
|
||||
export function configPwaConfig(env: ViteEnv, isBulid: boolean) {
|
||||
const { VITE_USE_PWA, VITE_GLOB_APP_TITLE, VITE_GLOB_APP_SHORT_NAME } = env;
|
||||
|
||||
const pwaPlugin = VitePWA({
|
||||
manifest: {
|
||||
name: 'Vben Admin',
|
||||
short_name: 'vben_admin',
|
||||
icons: [
|
||||
{
|
||||
src: './resource/img/pwa-192x192.png',
|
||||
sizes: '192x192',
|
||||
type: 'image/png',
|
||||
},
|
||||
{
|
||||
src: './resource/img/pwa-512x512.png',
|
||||
sizes: '512x512',
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
if (VITE_USE_PWA) {
|
||||
plugins.push(pwaPlugin);
|
||||
if (VITE_USE_PWA && isBulid) {
|
||||
// vite-plugin-pwa
|
||||
const pwaPlugin = VitePWA({
|
||||
manifest: {
|
||||
name: VITE_GLOB_APP_TITLE,
|
||||
short_name: VITE_GLOB_APP_SHORT_NAME,
|
||||
icons: [
|
||||
{
|
||||
src: './resource/img/pwa-192x192.png',
|
||||
sizes: '192x192',
|
||||
type: 'image/png',
|
||||
},
|
||||
{
|
||||
src: './resource/img/pwa-512x512.png',
|
||||
sizes: '512x512',
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
return pwaPlugin;
|
||||
}
|
||||
return plugins;
|
||||
return [];
|
||||
}
|
||||
|
@@ -1,54 +0,0 @@
|
||||
// Used to import all files under `src/views`
|
||||
// The built-in dynamic import of vite cannot meet the needs of importing all files under views
|
||||
// Special usage ,Only for this project
|
||||
import glob from 'glob';
|
||||
import { Transform } from 'vite/dist/node/transform.js';
|
||||
|
||||
function getPath(path: string) {
|
||||
const lastIndex = path.lastIndexOf('.');
|
||||
if (lastIndex !== -1) {
|
||||
path = path.substring(0, lastIndex);
|
||||
}
|
||||
return path.replace('src/views', '');
|
||||
}
|
||||
|
||||
const dynamicImportTransform = function (enableDynamicImport: boolean): Transform {
|
||||
return {
|
||||
test({ path }) {
|
||||
// Only convert the file
|
||||
return (
|
||||
path.includes('/src/router/helper/dynamicImport.ts') ||
|
||||
path.includes(`\\src\\router\\helper\\dynamicImport.ts`)
|
||||
);
|
||||
},
|
||||
transform({ code }) {
|
||||
if (!enableDynamicImport) {
|
||||
return code;
|
||||
}
|
||||
|
||||
// Only convert the dir
|
||||
try {
|
||||
const files = glob.sync('src/views/**/**.{vue,tsx}', { cwd: process.cwd() });
|
||||
|
||||
return `
|
||||
export default function (id) {
|
||||
switch (id) {
|
||||
${files
|
||||
.map((p) =>
|
||||
` case '${getPath(p)}': return () => import('${p
|
||||
.replace('src/views', '/@/views')
|
||||
.replace(/\/\//g, '/')}');`.replace('.tsx', '')
|
||||
)
|
||||
.join('\n ')}
|
||||
default: return Promise.reject(new Error("Unknown variable dynamic import: " + id));
|
||||
}
|
||||
}\n\n
|
||||
`;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return code;
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
export default dynamicImportTransform;
|
@@ -1,222 +0,0 @@
|
||||
// Modified from
|
||||
// https://github.com/luxueyan/vite-transform-globby-import/blob/master/src/index.ts
|
||||
|
||||
// TODO Deleting files requires re-running the project
|
||||
import { join } from 'path';
|
||||
import { lstatSync } from 'fs';
|
||||
import glob from 'glob';
|
||||
import globrex from 'globrex';
|
||||
import dotProp from 'dot-prop';
|
||||
import { createResolver, Resolver } from 'vite/dist/node/resolver.js';
|
||||
import { Transform } from 'vite/dist/node/transform.js';
|
||||
|
||||
const modulesDir: string = join(process.cwd(), '/node_modules/');
|
||||
|
||||
interface SharedConfig {
|
||||
root?: string;
|
||||
alias?: Record<string, string>;
|
||||
resolvers?: Resolver[];
|
||||
|
||||
includes?: string[];
|
||||
}
|
||||
|
||||
function template(template: string) {
|
||||
return (data: { [x: string]: any }) => {
|
||||
return template.replace(/#([^#]+)#/g, (_, g1) => data[g1] || g1);
|
||||
};
|
||||
}
|
||||
|
||||
// TODO support hmr
|
||||
function hmr(isBuild = false) {
|
||||
if (isBuild) return '';
|
||||
return `
|
||||
if (import.meta.hot) {
|
||||
import.meta.hot.accept();
|
||||
}`;
|
||||
}
|
||||
|
||||
// handle includes
|
||||
function fileInclude(includes: string | string[] | undefined, filePath: string) {
|
||||
return !includes || !Array.isArray(includes)
|
||||
? true
|
||||
: includes.some((item) => filePath.startsWith(item));
|
||||
}
|
||||
|
||||
// Bare exporter
|
||||
function compareString(modify: any, data: string[][]) {
|
||||
return modify ? '\n' + data.map((v) => `${v[0]}._path = ${v[1]}`).join('\n') : '';
|
||||
}
|
||||
|
||||
function varTemplate(data: string[][], name: string) {
|
||||
//prepare deep data (for locales)
|
||||
let deepData: Record<string, object | string> = {};
|
||||
let hasDeepData = false;
|
||||
|
||||
//data modify
|
||||
data.map((v) => {
|
||||
//check for has deep data
|
||||
if (v[0].includes('/')) {
|
||||
hasDeepData = true;
|
||||
}
|
||||
|
||||
// lastKey is a data
|
||||
let pathValue = v[0].replace(/\//g, '.').split('.');
|
||||
// let scopeKey = '';
|
||||
// const len=pathValue.length
|
||||
// const scope=pathValue[len-2]
|
||||
let lastKey: string | undefined = pathValue.pop();
|
||||
|
||||
let deepValue: Record<any, any> = {};
|
||||
if (lastKey) {
|
||||
// Solve the problem of files with the same name in different folders
|
||||
const lastKeyList = lastKey.replace('_' + pathValue[0], '').split('_');
|
||||
const key = lastKeyList.pop();
|
||||
if (key) {
|
||||
deepValue[key] = lastKey;
|
||||
}
|
||||
}
|
||||
// Set Deep Value
|
||||
deepValue = Object.assign(deepValue, dotProp.get(deepData, pathValue.join('.')));
|
||||
dotProp.set(deepData, pathValue.join('.'), deepValue);
|
||||
});
|
||||
|
||||
if (hasDeepData) {
|
||||
return `const ${name} = ` + JSON.stringify(deepData).replace(/\"|\'/g, '');
|
||||
}
|
||||
|
||||
return `const ${name} = { ${data.map((v) => v[0]).join(',')} }`;
|
||||
}
|
||||
|
||||
const globTransform = function (config: SharedConfig): Transform {
|
||||
const resolver = createResolver(
|
||||
config.root || process.cwd(),
|
||||
config.resolvers || [],
|
||||
config.alias || {}
|
||||
);
|
||||
const { includes } = config;
|
||||
const cache = new Map();
|
||||
const urlMap = new Map();
|
||||
return {
|
||||
test({ path }) {
|
||||
const filePath = path.replace('\u0000', ''); // why some path startsWith '\u0000'?
|
||||
|
||||
try {
|
||||
return (
|
||||
!filePath.startsWith(modulesDir) &&
|
||||
/\.(vue|js|jsx|ts|tsx)$/.test(filePath) &&
|
||||
fileInclude(includes, filePath) &&
|
||||
lstatSync(filePath).isFile()
|
||||
);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
transform({ code, path, isBuild }) {
|
||||
let result = cache.get(path);
|
||||
if (!result) {
|
||||
const reg = /import\s+([\w\s{}*]+)\s+from\s+(['"])globby(\?locale)?(\?path)?!([^'"]+)\2/g;
|
||||
const match = code.match(reg);
|
||||
if (!match) return code;
|
||||
const lastImport = urlMap.get(path);
|
||||
if (lastImport && match) {
|
||||
code = code.replace(lastImport, match[0]);
|
||||
}
|
||||
result = code.replace(
|
||||
reg,
|
||||
(
|
||||
_,
|
||||
// variable to export
|
||||
exportName,
|
||||
// bare export or not
|
||||
bareExporter,
|
||||
// is locale import
|
||||
isLocale,
|
||||
// inject _path attr
|
||||
injectPath,
|
||||
// path export
|
||||
globPath
|
||||
) => {
|
||||
const filePath = path.replace('\u0000', ''); // why some path startsWith '\u0000'?
|
||||
// resolve path
|
||||
|
||||
const resolvedFilePath = globPath.startsWith('.')
|
||||
? resolver.resolveRelativeRequest(filePath, globPath)
|
||||
: { pathname: resolver.requestToFile(globPath) };
|
||||
|
||||
const files = glob.sync(resolvedFilePath.pathname, { dot: true });
|
||||
|
||||
let templateStr = 'import #name# from #file#'; // import default
|
||||
let name = exportName;
|
||||
const m = exportName.match(/\{\s*(\w+)(\s+as\s+(\w+))?\s*\}/); // import module
|
||||
const m2 = exportName.match(/\*\s+as\s+(\w+)/); // import * as all module
|
||||
if (m) {
|
||||
templateStr = `import { ${m[1]} as #name# } from #file#`;
|
||||
name = m[3] || m[1];
|
||||
} else if (m2) {
|
||||
templateStr = 'import * as #name# from #file#';
|
||||
name = m2[1];
|
||||
}
|
||||
|
||||
const templateRender = template(templateStr);
|
||||
|
||||
const groups: Array<string>[] = [];
|
||||
const replaceFiles = files.map((f, i) => {
|
||||
const filePath = resolver.fileToRequest(f);
|
||||
const file = bareExporter + filePath + bareExporter;
|
||||
|
||||
if (isLocale) {
|
||||
const globrexRes = globrex(globPath, { extended: true, globstar: true });
|
||||
|
||||
// Get segments for files like an en/system ch/modules for:
|
||||
// ['en', 'system'] ['ch', 'modules']
|
||||
|
||||
// TODO The window system and mac system path are inconsistent?
|
||||
const fileNameWithAlias = filePath.replace(/^(\/src\/)/, '/@/');
|
||||
const matchedGroups = globrexRes.regex.exec(fileNameWithAlias);
|
||||
|
||||
if (matchedGroups && matchedGroups.length) {
|
||||
const matchedSegments = matchedGroups[1]; //first everytime "Full Match"
|
||||
const matchList = matchedSegments.split('/').filter(Boolean);
|
||||
const lang = matchList.shift();
|
||||
const scope = matchList.pop();
|
||||
|
||||
// Solve the problem of files with the same name in different folders
|
||||
const scopeKey = scope ? `${scope}_` : '';
|
||||
const fileName = matchedGroups[2];
|
||||
const name = scopeKey + fileName + '_' + lang;
|
||||
|
||||
//send deep way like an (en/modules/system/dashboard) into groups
|
||||
groups.push([matchedSegments + name, file]);
|
||||
return templateRender({
|
||||
name,
|
||||
file,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
groups.push([name + i, file]);
|
||||
return templateRender({ name: name + i, file });
|
||||
}
|
||||
});
|
||||
// save in memory used result
|
||||
const filesJoined = replaceFiles.join('\n');
|
||||
|
||||
urlMap.set(path, filesJoined);
|
||||
|
||||
// console.log('======================');
|
||||
// console.log(filesJoined, varTemplate(groups, name));
|
||||
// console.log('======================');
|
||||
return [
|
||||
filesJoined,
|
||||
compareString(injectPath, groups),
|
||||
varTemplate(groups, name),
|
||||
'',
|
||||
].join('\n');
|
||||
}
|
||||
);
|
||||
if (isBuild) cache.set(path, result);
|
||||
}
|
||||
return `${result}${hmr(isBuild)}`;
|
||||
},
|
||||
};
|
||||
};
|
||||
export default globTransform;
|
@@ -1,16 +1,10 @@
|
||||
import type { ServerOptions } from 'http-proxy';
|
||||
|
||||
type ProxyItem = [string, string];
|
||||
|
||||
type ProxyList = ProxyItem[];
|
||||
|
||||
type ProxyTargetList = Record<
|
||||
string,
|
||||
{
|
||||
target: string;
|
||||
changeOrigin: boolean;
|
||||
rewrite: (path: string) => any;
|
||||
secure?: boolean;
|
||||
}
|
||||
>;
|
||||
type ProxyTargetList = Record<string, ServerOptions & { rewrite: (path: string) => string }>;
|
||||
|
||||
const httpsRE = /^https:\/\//;
|
||||
|
||||
@@ -23,9 +17,11 @@ export function createProxy(list: ProxyList = []) {
|
||||
for (const [prefix, target] of list) {
|
||||
const isHttps = httpsRE.test(target);
|
||||
|
||||
// https://github.com/http-party/node-http-proxy#options
|
||||
ret[prefix] = {
|
||||
target: target,
|
||||
changeOrigin: true,
|
||||
ws: true,
|
||||
rewrite: (path) => path.replace(new RegExp(`^${prefix}`), ''),
|
||||
// https is require secure=false
|
||||
...(isHttps ? { secure: false } : {}),
|
||||
|
12
index.html
12
index.html
@@ -1,7 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<%= viteHtmlPluginOptions.hmScript %>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="renderer" content="webkit" />
|
||||
@@ -10,9 +9,8 @@
|
||||
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
|
||||
/>
|
||||
|
||||
<title></title>
|
||||
<title><%= title %></title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<%= viteHtmlPluginOptions.injectConfig %>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
@@ -137,15 +135,11 @@
|
||||
</style>
|
||||
<div class="app-loading">
|
||||
<div class="app-loading-wrap">
|
||||
<img
|
||||
src="<%= viteHtmlPluginOptions.publicPath %>resource/img/logo.png"
|
||||
class="app-loading-logo"
|
||||
alt="Logo"
|
||||
/>
|
||||
<img src="/resource/img/logo.png" class="app-loading-logo" alt="Logo" />
|
||||
<div class="app-loading-dots">
|
||||
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
|
||||
</div>
|
||||
<div class="app-loading-title"><%= viteHtmlPluginOptions.title %></div>
|
||||
<div class="app-loading-title"><%= title %></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
45
package.json
45
package.json
@@ -1,20 +1,17 @@
|
||||
{
|
||||
"name": "vben-admin",
|
||||
"version": "2.0.0-rc.15",
|
||||
"version": "2.0.0-rc.16",
|
||||
"scripts": {
|
||||
"bootstrap": "yarn install",
|
||||
"serve": "cross-env vite --mode=development",
|
||||
"build": "cross-env vite build --mode=production && esno ./build/script/postBuild.ts",
|
||||
"build:site": "cross-env SITE=true npm run build ",
|
||||
"serve": "cross-env vite ",
|
||||
"build": "cross-env vite build && esno ./build/script/postBuild.ts",
|
||||
"build:no-cache": "yarn clean:cache && npm run build",
|
||||
"typecheck": "vuedx-typecheck .",
|
||||
"report": "cross-env REPORT=true npm run build ",
|
||||
"preview": "npm run build && esno ./build/script/preview.ts",
|
||||
"preview:dist": "esno ./build/script/preview.ts",
|
||||
"log": "esno ./build/script/changelog.ts",
|
||||
"log": "conventional-changelog -p custom-config -i CHANGELOG.md -s -r 0",
|
||||
"clean:cache": "rimraf node_modules/.cache/ && rimraf node_modules/.vite_opt_cache",
|
||||
"clean:lib": "npx rimraf node_modules",
|
||||
"ls-lint": "npx ls-lint",
|
||||
"lint:eslint": "eslint --fix --ext \"src/**/*.{vue,less,css,scss}\"",
|
||||
"lint:prettier": "prettier --write --loglevel warn \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
|
||||
"lint:stylelint": "stylelint --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
|
||||
@@ -22,7 +19,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@iconify/iconify": "^2.0.0-rc.5",
|
||||
"@vueuse/core": "^4.0.2",
|
||||
"@vueuse/core": "^4.0.5",
|
||||
"ant-design-vue": "^2.0.0-rc.8",
|
||||
"apexcharts": "^3.23.1",
|
||||
"axios": "^0.21.1",
|
||||
@@ -34,26 +31,27 @@
|
||||
"nprogress": "^0.2.0",
|
||||
"path-to-regexp": "^6.2.0",
|
||||
"qrcode": "^1.4.4",
|
||||
"sortablejs": "^1.12.0",
|
||||
"sortablejs": "^1.13.0",
|
||||
"vditor": "^3.7.5",
|
||||
"vue": "^3.0.5",
|
||||
"vue-i18n": "9.0.0-beta.14",
|
||||
"vue-i18n": "^9.0.0-rc.1",
|
||||
"vue-router": "^4.0.2",
|
||||
"vue-types": "^3.0.1",
|
||||
"vuex": "^4.0.0-rc.2",
|
||||
"vuex-module-decorators": "^1.0.1",
|
||||
"xlsx": "^0.16.9",
|
||||
"zxcvbn": "^4.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.10",
|
||||
"@commitlint/cli": "^11.0.0",
|
||||
"@commitlint/config-conventional": "^11.0.0",
|
||||
"@iconify/json": "^1.1.282",
|
||||
"@iconify/json": "^1.1.283",
|
||||
"@ls-lint/ls-lint": "^1.9.2",
|
||||
"@purge-icons/generated": "^0.4.1",
|
||||
"@purge-icons/generated": "^0.5.0",
|
||||
"@types/echarts": "^4.9.3",
|
||||
"@types/fs-extra": "^9.0.6",
|
||||
"@types/globrex": "^0.1.0",
|
||||
"@types/http-proxy": "^1.17.4",
|
||||
"@types/koa-static": "^4.0.1",
|
||||
"@types/lodash-es": "^4.17.4",
|
||||
"@types/mockjs": "^1.0.3",
|
||||
@@ -65,10 +63,13 @@
|
||||
"@types/zxcvbn": "^4.4.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.12.0",
|
||||
"@typescript-eslint/parser": "^4.12.0",
|
||||
"@vitejs/plugin-legacy": "^1.1.0",
|
||||
"@vitejs/plugin-vue": "^1.0.4",
|
||||
"@vitejs/plugin-vue-jsx": "^1.0.1",
|
||||
"@vue/compiler-sfc": "^3.0.5",
|
||||
"@vuedx/typecheck": "^0.4.1",
|
||||
"@vuedx/typescript-plugin-vue": "^0.4.1",
|
||||
"autoprefixer": "^9.8.6",
|
||||
"autoprefixer": "^10.2.1",
|
||||
"commitizen": "^4.2.2",
|
||||
"conventional-changelog-cli": "^2.1.1",
|
||||
"conventional-changelog-custom-config": "^0.3.1",
|
||||
@@ -82,14 +83,15 @@
|
||||
"esno": "^0.4.0",
|
||||
"fs-extra": "^9.0.1",
|
||||
"globrex": "^0.1.2",
|
||||
"husky": "^4.3.6",
|
||||
"husky": "^4.3.7",
|
||||
"koa-static": "^5.0.0",
|
||||
"less": "^4.0.0",
|
||||
"lint-staged": "^10.5.3",
|
||||
"portfinder": "^1.0.28",
|
||||
"postcss-import": "^12.0.1",
|
||||
"postcss-import": "^14.0.0",
|
||||
"prettier": "^2.2.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup-plugin-gzip": "^2.5.0",
|
||||
"rollup-plugin-visualizer": "^4.1.2",
|
||||
"stylelint": "^13.8.0",
|
||||
"stylelint-config-prettier": "^8.0.2",
|
||||
@@ -98,11 +100,12 @@
|
||||
"tasksfile": "^5.1.1",
|
||||
"ts-node": "^9.1.0",
|
||||
"typescript": "^4.1.3",
|
||||
"vite": "^1.0.0-rc.13",
|
||||
"vite-plugin-html": "^1.0.0-beta.2",
|
||||
"vite-plugin-mock": "^1.0.9",
|
||||
"vite-plugin-purge-icons": "^0.4.5",
|
||||
"vite-plugin-pwa": "^0.2.1",
|
||||
"vite": "^2.0.0-beta.15",
|
||||
"vite-plugin-html": "^2.0.0-beta.5",
|
||||
"vite-plugin-import-context": "^1.0.0-rc.1",
|
||||
"vite-plugin-mock": "^2.0.0-beta.1",
|
||||
"vite-plugin-purge-icons": "^0.5.0",
|
||||
"vite-plugin-pwa": "^0.3.2",
|
||||
"vue-eslint-parser": "^7.3.0",
|
||||
"yargs": "^16.2.0"
|
||||
},
|
||||
|
@@ -13,7 +13,7 @@
|
||||
import { initAppConfigStore } from '/@/setup/App';
|
||||
|
||||
import { useLockPage } from '/@/hooks/web/useLockPage';
|
||||
import { useLocale } from '/@/hooks/web/useLocale';
|
||||
import { useLocale } from '/@/locales/useLocale';
|
||||
|
||||
import { AppProvider } from '/@/components/Application';
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
name: 'App',
|
||||
components: { ConfigProvider, AppProvider },
|
||||
setup() {
|
||||
const { antConfigLocale, setLocale } = useLocale();
|
||||
setLocale();
|
||||
|
||||
// Initialize vuex internal system configuration
|
||||
initAppConfigStore();
|
||||
|
||||
@@ -28,7 +31,6 @@
|
||||
const lockEvent = useLockPage();
|
||||
|
||||
// support Multi-language
|
||||
const { antConfigLocale } = useLocale();
|
||||
|
||||
return {
|
||||
antConfigLocale,
|
||||
|
@@ -22,7 +22,7 @@
|
||||
import { Dropdown, DropMenu } from '/@/components/Dropdown';
|
||||
import { GlobalOutlined } from '@ant-design/icons-vue';
|
||||
|
||||
import { useLocale } from '/@/hooks/web/useLocale';
|
||||
import { useLocale } from '/@/locales/useLocale';
|
||||
import { useLocaleSetting } from '/@/hooks/setting/useLocaleSetting';
|
||||
|
||||
import { LocaleType } from '/@/locales/types';
|
||||
@@ -75,7 +75,6 @@
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-app-locale-picker';
|
||||
|
||||
:global(.@{prefix-cls}-overlay) {
|
||||
|
@@ -59,7 +59,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-app-logo';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -44,7 +44,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-app-search';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -37,7 +37,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-app-search-footer';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -123,7 +123,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-app-search-modal';
|
||||
@footer-prefix-cls: ~'@{namespace}-app-search-footer';
|
||||
.@{prefix-cls} {
|
||||
|
@@ -46,7 +46,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-basic-arrow';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -112,7 +112,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-basic-help';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -30,7 +30,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-basic-title';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -140,7 +140,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-lazy-container';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -12,7 +12,7 @@
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ScrollContainer',
|
||||
inheritAttrs: false,
|
||||
// inheritAttrs: false,
|
||||
components: { Scrollbar },
|
||||
setup() {
|
||||
const scrollbarRef = ref<Nullable<ScrollbarType>>(null);
|
||||
|
@@ -87,7 +87,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-collapse-container';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -1,5 +1,3 @@
|
||||
@import (reference) '../../../design/index.less';
|
||||
|
||||
@default-height: 42px !important;
|
||||
|
||||
@small-height: 36px !important;
|
||||
|
@@ -76,9 +76,7 @@ export default defineComponent({
|
||||
return (
|
||||
<>
|
||||
<Menu.Item disabled={disabled} class={`${prefixCls}__item`} key={label}>
|
||||
{() => [
|
||||
<ItemContent showIcon={props.showIcon} item={item} handler={handleAction} />,
|
||||
]}
|
||||
<ItemContent showIcon={props.showIcon} item={item} handler={handleAction} />
|
||||
</Menu.Item>
|
||||
{DividerComp}
|
||||
</>
|
||||
@@ -109,7 +107,7 @@ export default defineComponent({
|
||||
ref={wrapRef}
|
||||
style={unref(getStyle)}
|
||||
>
|
||||
{() => renderMenuItem(items)}
|
||||
{renderMenuItem(items)}
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
|
@@ -114,7 +114,7 @@ export default defineComponent({
|
||||
const renderDesc = () => {
|
||||
return (
|
||||
<Descriptions class={`${prefixCls}`} {...(unref(getDescriptionsProps) as any)}>
|
||||
{() => renderItem()}
|
||||
{renderItem()}
|
||||
</Descriptions>
|
||||
);
|
||||
};
|
||||
|
@@ -199,7 +199,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../design/index.less';
|
||||
@header-height: 60px;
|
||||
@detail-header-height: 40px;
|
||||
@prefix-cls: ~'@{namespace}-basic-drawer';
|
||||
|
@@ -66,7 +66,6 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import (reference) '../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-basic-drawer-footer';
|
||||
@footer-height: 60px;
|
||||
.@{prefix-cls} {
|
||||
|
@@ -45,7 +45,6 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import (reference) '../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-basic-drawer-header';
|
||||
@footer-height: 60px;
|
||||
.@{prefix-cls} {
|
||||
|
@@ -247,7 +247,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-basic-form';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -173,7 +173,8 @@ export default defineComponent({
|
||||
const characterInx = rules.findIndex((val) => val.max);
|
||||
if (characterInx !== -1 && !rules[characterInx].validator) {
|
||||
rules[characterInx].message =
|
||||
rules[characterInx].message || t('component.form.maxTip', [rules[characterInx].max]);
|
||||
rules[characterInx].message ||
|
||||
t('component.form.maxTip', [rules[characterInx].max] as Recordable);
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
@@ -294,12 +295,10 @@ export default defineComponent({
|
||||
labelCol={labelCol}
|
||||
wrapperCol={wrapperCol}
|
||||
>
|
||||
{() => (
|
||||
<>
|
||||
{getContent()}
|
||||
{showSuffix && <span class="suffix">{getSuffix}</span>}
|
||||
</>
|
||||
)}
|
||||
<>
|
||||
{getContent()}
|
||||
{showSuffix && <span class="suffix">{getSuffix}</span>}
|
||||
</>
|
||||
</Form.Item>
|
||||
);
|
||||
}
|
||||
@@ -323,7 +322,7 @@ export default defineComponent({
|
||||
return (
|
||||
isIfShow && (
|
||||
<Col {...realColProps} class={{ hidden: !isShow }}>
|
||||
{() => getContent()}
|
||||
{getContent()}
|
||||
</Col>
|
||||
)
|
||||
);
|
||||
|
@@ -83,8 +83,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../design/index.less';
|
||||
|
||||
.app-iconify {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
|
@@ -7,7 +7,7 @@
|
||||
import 'vditor/dist/index.css';
|
||||
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { useLocale } from '/@/hooks/web/useLocale';
|
||||
import { useLocale } from '/@/locales/useLocale';
|
||||
import { useModalContext } from '../../Modal';
|
||||
|
||||
type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined;
|
||||
|
@@ -1,5 +1,3 @@
|
||||
@import (reference) '../../../design/index.less';
|
||||
|
||||
@basic-menu-prefix-cls: ~'@{namespace}-basic-menu';
|
||||
@basic-menu-content-prefix-cls: ~'@{namespace}-basic-menu-item-content';
|
||||
@basic-menu-tag-prefix-cls: ~'@{namespace}-basic-menu-item-tag';
|
||||
|
@@ -54,7 +54,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-basic-modal-close';
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
|
@@ -1,5 +1,3 @@
|
||||
@import (reference) '../../../design/index.less';
|
||||
|
||||
.fullscreen-modal {
|
||||
overflow: hidden;
|
||||
|
||||
@@ -79,7 +77,7 @@
|
||||
|
||||
&-confirm-body {
|
||||
.ant-modal-confirm-content {
|
||||
color: #fff;
|
||||
// color: #fff;
|
||||
|
||||
> * {
|
||||
color: @text-color-help-dark;
|
||||
|
@@ -1,4 +1,8 @@
|
||||
export { createImgPreview } from './src/functional';
|
||||
// export { createImgPreview } from './src/functional';
|
||||
|
||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||
export const ImagePreview = createAsyncComponent(() => import('./src/index.vue'));
|
||||
export const createImgPreview = () => {};
|
||||
|
||||
// import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||
// export const ImagePreview = createAsyncComponent(() => import('./src/index.vue'));
|
||||
|
||||
export { default as ImagePreview } from './src/index.vue';
|
||||
|
@@ -1,5 +1,3 @@
|
||||
@import (reference) '../../../design/index.less';
|
||||
|
||||
.img-preview {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
@@ -58,7 +58,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-image-preview';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -34,7 +34,7 @@
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Scrollbar',
|
||||
inheritAttrs: false,
|
||||
// inheritAttrs: false,
|
||||
components: { Bar },
|
||||
props: {
|
||||
native: {
|
||||
|
@@ -83,7 +83,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-strength-meter';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -1,5 +1,3 @@
|
||||
@import (reference) '../../../design/index.less';
|
||||
|
||||
.file-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
|
@@ -1,5 +1,3 @@
|
||||
@import (reference) '../../../design/index.less';
|
||||
|
||||
@radius: 4px;
|
||||
|
||||
.darg-verify {
|
||||
|
@@ -1,5 +1,3 @@
|
||||
@import (reference) '../../../design/index.less';
|
||||
|
||||
.ir-dv {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
@@ -35,25 +35,21 @@ import {
|
||||
Menu,
|
||||
Breadcrumb,
|
||||
} from 'ant-design-vue';
|
||||
import { getApp } from '/@/setup/App';
|
||||
import { App } from 'vue';
|
||||
|
||||
const compList = [Icon, Button, AntButton.Group];
|
||||
|
||||
// Fix hmr multiple registered components
|
||||
let registered = false;
|
||||
export function registerGlobComp() {
|
||||
if (registered) return;
|
||||
export function registerGlobComp(app: App) {
|
||||
compList.forEach((comp: any) => {
|
||||
getApp().component(comp.name, comp);
|
||||
app.component(comp.name, comp);
|
||||
});
|
||||
|
||||
registered = true;
|
||||
|
||||
// Optional
|
||||
// Why register here: The main reason for registering here is not to increase the size of the first screen code
|
||||
// If you need to customize global components, you can write here
|
||||
// If you don’t need it, you can delete it
|
||||
getApp()
|
||||
app
|
||||
.use(Select)
|
||||
.use(Alert)
|
||||
.use(Breadcrumb)
|
||||
|
@@ -4,7 +4,7 @@ import { computed, unref } from 'vue';
|
||||
import { appStore } from '/@/store/modules/app';
|
||||
|
||||
import getProjectSetting from '/@/settings/projectSetting';
|
||||
import { localeList } from '/@/locales';
|
||||
import { localeList } from '/@/locales/constant';
|
||||
|
||||
// Get locale configuration
|
||||
const getLocale = computed(() => appStore.getProjectConfig.locale || getProjectSetting.locale);
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { getI18n } from '/@/setup/i18n';
|
||||
import { i18n } from '/@/locales/setupI18n';
|
||||
|
||||
export function useI18n(namespace?: string) {
|
||||
function getKey(key: string) {
|
||||
@@ -16,18 +16,19 @@ export function useI18n(namespace?: string) {
|
||||
},
|
||||
};
|
||||
|
||||
if (!getI18n()) {
|
||||
if (!i18n) {
|
||||
return normalFn;
|
||||
}
|
||||
|
||||
const { t, ...methods } = getI18n().global;
|
||||
const { t, ...methods } = i18n.global;
|
||||
|
||||
const tFn = function (...arg: Parameters<typeof t>) {
|
||||
if (!arg[0]) return '';
|
||||
return t(getKey(arg[0]), ...(arg as Parameters<typeof t>));
|
||||
};
|
||||
return {
|
||||
...methods,
|
||||
t: (key: string, ...arg: any): string => {
|
||||
if (!key) return '';
|
||||
return t(getKey(key), ...(arg as Parameters<typeof t>));
|
||||
},
|
||||
t: tFn,
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -59,7 +59,7 @@ function createConfirm(options: ModalOptionsEx): ConfirmOptions {
|
||||
icon: getIcon(iconType),
|
||||
...options,
|
||||
};
|
||||
return Modal.confirm(opt) as any;
|
||||
return (Modal.confirm(opt) as unknown) as ConfirmOptions;
|
||||
}
|
||||
|
||||
const baseOptions = {
|
||||
|
@@ -18,7 +18,7 @@
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
|
||||
import PageLayout from '/@/layouts/page/index';
|
||||
import PageLayout from '/@/layouts/page/index.vue';
|
||||
import { useContentViewHeight } from './useContentViewHeight';
|
||||
import { Loading } from '/@/components/Loading';
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-layout-content';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -40,7 +40,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-layout-footer';
|
||||
|
||||
@normal-color: rgba(0, 0, 0, 0.45);
|
||||
|
@@ -109,7 +109,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-layout-multiple-header';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -147,7 +147,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-layout-breadcrumb';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -80,7 +80,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-header-lock-modal';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -49,7 +49,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-header-notify-list';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -49,7 +49,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-header-notify';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -99,7 +99,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-header-user-dropdown';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -1,4 +1,3 @@
|
||||
@import (reference) '../../../design/index.less';
|
||||
@header-trigger-prefix-cls: ~'@{namespace}-layout-header-trigger';
|
||||
@header-prefix-cls: ~'@{namespace}-layout-header';
|
||||
@locale-prefix-cls: ~'@{namespace}-app-locale-picker';
|
||||
|
@@ -31,7 +31,6 @@
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
|
||||
import { registerGlobComp } from '/@/components/registerGlobComp';
|
||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||
|
||||
export default defineComponent({
|
||||
@@ -46,11 +45,6 @@
|
||||
Layout,
|
||||
},
|
||||
setup() {
|
||||
// ! Only register global components here
|
||||
// ! Can reduce the size of the first screen code
|
||||
// default layout It is loaded after login. So it won’t be packaged to the first screen
|
||||
registerGlobComp();
|
||||
|
||||
const { prefixCls } = useDesign('default-layout');
|
||||
|
||||
const { getIsMobile } = useAppInject();
|
||||
@@ -70,7 +64,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-default-layout';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -1,5 +1,3 @@
|
||||
@import (reference) '../../../design/index.less';
|
||||
|
||||
@prefix-cls: ~'@{namespace}-layout-menu';
|
||||
@logo-prefix-cls: ~'@{namespace}-app-logo';
|
||||
|
||||
|
@@ -389,26 +389,20 @@ export default defineComponent({
|
||||
width={330}
|
||||
wrapClassName="setting-drawer"
|
||||
>
|
||||
{{
|
||||
default: () => (
|
||||
<>
|
||||
<Divider>{() => t('layout.setting.navMode')}</Divider>
|
||||
{renderSidebar()}
|
||||
<Divider>{() => t('layout.setting.headerTheme')}</Divider>
|
||||
{renderHeaderTheme()}
|
||||
<Divider>{() => t('layout.setting.sidebarTheme')}</Divider>
|
||||
{renderSiderTheme()}
|
||||
<Divider>{() => t('layout.setting.interfaceFunction')}</Divider>
|
||||
{renderFeatures()}
|
||||
<Divider>{() => t('layout.setting.interfaceDisplay')}</Divider>
|
||||
{renderContent()}
|
||||
<Divider>{() => t('layout.setting.animation')}</Divider>
|
||||
{renderTransition()}
|
||||
<Divider />
|
||||
<SettingFooter />
|
||||
</>
|
||||
),
|
||||
}}
|
||||
<Divider>{() => t('layout.setting.navMode')}</Divider>
|
||||
{renderSidebar()}
|
||||
<Divider>{() => t('layout.setting.headerTheme')}</Divider>
|
||||
{renderHeaderTheme()}
|
||||
<Divider>{() => t('layout.setting.sidebarTheme')}</Divider>
|
||||
{renderSiderTheme()}
|
||||
<Divider>{() => t('layout.setting.interfaceFunction')}</Divider>
|
||||
{renderFeatures()}
|
||||
<Divider>{() => t('layout.setting.interfaceDisplay')}</Divider>
|
||||
{renderContent()}
|
||||
<Divider>{() => t('layout.setting.animation')}</Divider>
|
||||
{renderTransition()}
|
||||
<Divider />
|
||||
<SettingFooter />
|
||||
</BasicDrawer>
|
||||
);
|
||||
},
|
||||
|
@@ -43,7 +43,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-setting-input-number-item';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -62,7 +62,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-setting-select-item';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -75,7 +75,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-setting-footer';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -57,7 +57,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-setting-switch-item';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -55,7 +55,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-setting-theme-picker';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -51,7 +51,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-setting-menu-type-picker';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -28,7 +28,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-setting-button';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -41,7 +41,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-darg-bar';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -128,7 +128,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-layout-sideBar';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -333,7 +333,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-layout-mix-sider';
|
||||
@tag-prefix-cls: ~'@{namespace}-basic-menu-item-tag';
|
||||
@width: 80px;
|
||||
|
@@ -41,7 +41,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-layout-sider-wrapper';
|
||||
.@{prefix-cls} {
|
||||
.ant-drawer-body {
|
||||
|
@@ -1,4 +1,3 @@
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-multiple-tabs';
|
||||
|
||||
.@{prefix-cls} {
|
||||
|
@@ -1,72 +0,0 @@
|
||||
import type { DefaultContext } from './transition';
|
||||
|
||||
import { computed, defineComponent, unref, Transition, KeepAlive } from 'vue';
|
||||
import { RouterView } from 'vue-router';
|
||||
|
||||
import FrameLayout from '/@/layouts/iframe/index.vue';
|
||||
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
|
||||
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
|
||||
import { useCache } from './useCache';
|
||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
||||
import { getTransitionName } from './transition';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'PageLayout',
|
||||
setup() {
|
||||
const { getCaches } = useCache(true);
|
||||
const { getShowMultipleTab } = useMultipleTabSetting();
|
||||
|
||||
const { getOpenKeepAlive, getCanEmbedIFramePage } = useRootSetting();
|
||||
|
||||
const { getBasicTransition, getEnableTransition } = useTransitionSetting();
|
||||
|
||||
const openCache = computed(() => unref(getOpenKeepAlive) && unref(getShowMultipleTab));
|
||||
|
||||
return () => {
|
||||
return (
|
||||
<>
|
||||
<RouterView>
|
||||
{{
|
||||
default: ({ Component, route }: DefaultContext) => {
|
||||
// No longer show animations that are already in the tab
|
||||
const cacheTabs = unref(getCaches);
|
||||
|
||||
const name = getTransitionName({
|
||||
route,
|
||||
openCache: unref(openCache),
|
||||
enableTransition: unref(getEnableTransition),
|
||||
cacheTabs,
|
||||
def: unref(getBasicTransition),
|
||||
});
|
||||
|
||||
// When the child element is the parentView, adding the key will cause the component to be executed multiple times. When it is not parentView, you need to add a key, because it needs to be compatible with the same route carrying different parameters
|
||||
const isParentView = Component?.type.parentView;
|
||||
const componentKey = isParentView ? {} : { key: route.fullPath };
|
||||
|
||||
const renderComp = () => <Component {...componentKey} />;
|
||||
|
||||
const PageContent = unref(openCache) ? (
|
||||
<KeepAlive include={cacheTabs}>{renderComp()}</KeepAlive>
|
||||
) : (
|
||||
renderComp()
|
||||
);
|
||||
|
||||
if (!unref(getEnableTransition)) {
|
||||
return PageContent;
|
||||
}
|
||||
return (
|
||||
<Transition name={name} mode="out-in" appear={true}>
|
||||
{() => PageContent}
|
||||
</Transition>
|
||||
);
|
||||
},
|
||||
}}
|
||||
</RouterView>
|
||||
{unref(getCanEmbedIFramePage) && <FrameLayout />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
72
src/layouts/page/index.vue
Normal file
72
src/layouts/page/index.vue
Normal file
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<div>
|
||||
<router-view>
|
||||
<template v-slot="{ Component, route }">
|
||||
<transition
|
||||
:name="
|
||||
getTransitionName({
|
||||
route,
|
||||
openCache,
|
||||
enableTransition: getEnableTransition,
|
||||
cacheTabs: getCaches,
|
||||
def: getBasicTransition,
|
||||
})
|
||||
"
|
||||
mode="out-in"
|
||||
appear
|
||||
>
|
||||
<keep-alive v-if="openCache" :include="getCaches">
|
||||
<component :is="Component" v-bind="getKey(Component, route)" />
|
||||
</keep-alive>
|
||||
<component v-else :is="Component" v-bind="getKey(Component, route)" />
|
||||
</transition>
|
||||
</template>
|
||||
</router-view>
|
||||
<FrameLayout v-if="getCanEmbedIFramePage" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { FunctionalComponent } from 'vue';
|
||||
import type { RouteLocation } from 'vue-router';
|
||||
|
||||
import { computed, defineComponent, unref } from 'vue';
|
||||
|
||||
import FrameLayout from '/@/layouts/iframe/index.vue';
|
||||
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
|
||||
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
|
||||
import { useCache } from './useCache';
|
||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
||||
import { getTransitionName } from './transition';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'PageLayout',
|
||||
components: { FrameLayout },
|
||||
setup() {
|
||||
const { getCaches } = useCache(true);
|
||||
const { getShowMultipleTab } = useMultipleTabSetting();
|
||||
|
||||
const { getOpenKeepAlive, getCanEmbedIFramePage } = useRootSetting();
|
||||
|
||||
const { getBasicTransition, getEnableTransition } = useTransitionSetting();
|
||||
|
||||
const openCache = computed(() => unref(getOpenKeepAlive) && unref(getShowMultipleTab));
|
||||
|
||||
function getKey(component: FunctionalComponent & { type: Indexable }, route: RouteLocation) {
|
||||
return !!component?.type.parentView ? {} : { key: route.fullPath };
|
||||
}
|
||||
|
||||
return {
|
||||
getTransitionName,
|
||||
openCache,
|
||||
getEnableTransition,
|
||||
getBasicTransition,
|
||||
getCaches,
|
||||
getCanEmbedIFramePage,
|
||||
getKey,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
@@ -1,5 +1,3 @@
|
||||
import messages from 'globby?locale!/@/locales/lang/**/*.@(ts)';
|
||||
|
||||
import type { DropMenu } from '/@/components/Dropdown';
|
||||
|
||||
// locale list
|
||||
@@ -13,4 +11,3 @@ export const localeList: DropMenu[] = [
|
||||
event: 'en',
|
||||
},
|
||||
];
|
||||
export default messages;
|
4
src/locales/getMessage.ts
Normal file
4
src/locales/getMessage.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { genMessage } from './helper';
|
||||
import modules from 'glob:./lang/**/*.ts';
|
||||
|
||||
export default genMessage(modules);
|
20
src/locales/helper.ts
Normal file
20
src/locales/helper.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { set } from 'lodash-es';
|
||||
|
||||
export function genMessage(langs: Record<string, Record<string, any>>, prefix = 'lang') {
|
||||
const obj: Recordable = {};
|
||||
|
||||
Object.keys(langs).forEach((key) => {
|
||||
const mod = langs[key].default;
|
||||
let k = key.replace(`./${prefix}/`, '').replace(/^\.\//, '');
|
||||
const lastIndex = k.lastIndexOf('.');
|
||||
k = k.substring(0, lastIndex);
|
||||
const keyList = k.split('/');
|
||||
const lang = keyList.shift();
|
||||
const objKey = keyList.join('.');
|
||||
if (lang) {
|
||||
set(obj, lang, obj[lang] || {});
|
||||
set(obj[lang], objKey, mod);
|
||||
}
|
||||
});
|
||||
return obj;
|
||||
}
|
@@ -1,34 +1,31 @@
|
||||
import { App } from 'vue';
|
||||
import type { App } from 'vue';
|
||||
import type { I18n, I18nOptions } from 'vue-i18n';
|
||||
|
||||
import { createI18n } from 'vue-i18n';
|
||||
import localeMessages from '/@/locales';
|
||||
import { useLocale } from '/@/hooks/web/useLocale';
|
||||
|
||||
import 'moment/dist/locale/zh-cn';
|
||||
|
||||
import projectSetting from '/@/settings/projectSetting';
|
||||
const { setupLocale } = useLocale();
|
||||
|
||||
import messages from './getMessage';
|
||||
|
||||
const { lang, availableLocales, fallback } = projectSetting?.locale;
|
||||
|
||||
const localeData: I18nOptions = {
|
||||
legacy: false,
|
||||
locale: lang,
|
||||
fallbackLocale: fallback,
|
||||
messages: localeMessages,
|
||||
messages,
|
||||
availableLocales: availableLocales,
|
||||
sync: true, //If you don’t want to inherit locale from global scope, you need to set sync of i18n component option to false.
|
||||
silentTranslationWarn: true, // true - warning off
|
||||
missingWarn: false,
|
||||
silentFallbackWarn: true,
|
||||
};
|
||||
|
||||
let i18n: I18n;
|
||||
export let i18n: I18n;
|
||||
|
||||
// setup i18n instance with glob
|
||||
export function setupI18n(app: App) {
|
||||
i18n = createI18n(localeData) as I18n;
|
||||
setupLocale();
|
||||
app.use(i18n);
|
||||
}
|
||||
|
||||
export function getI18n(): I18n {
|
||||
return i18n;
|
||||
}
|
@@ -2,18 +2,16 @@
|
||||
* Multi-language related operations
|
||||
*/
|
||||
import type { LocaleType } from '/@/locales/types';
|
||||
import type { Ref } from 'vue';
|
||||
|
||||
import { unref, ref } from 'vue';
|
||||
|
||||
import { getI18n } from '/@/setup/i18n';
|
||||
|
||||
import { useLocaleSetting } from '/@/hooks/setting/useLocaleSetting';
|
||||
|
||||
import moment from 'moment';
|
||||
|
||||
import 'moment/dist/locale/zh-cn';
|
||||
|
||||
moment.locale('zh-cn');
|
||||
import { i18n } from './setupI18n';
|
||||
|
||||
const antConfigLocaleRef = ref<any>(null);
|
||||
|
||||
@@ -23,7 +21,11 @@ export function useLocale() {
|
||||
// Switching the language will change the locale of useI18n
|
||||
// And submit to configuration modification
|
||||
function changeLocale(lang: LocaleType): void {
|
||||
(getI18n().global.locale as any).value = lang;
|
||||
if (i18n.mode === 'legacy') {
|
||||
i18n.global.locale = lang;
|
||||
} else {
|
||||
((i18n.global.locale as unknown) as Ref<string>).value = lang;
|
||||
}
|
||||
setLocalSetting({ lang });
|
||||
// i18n.global.setLocaleMessage(locale, messages);
|
||||
|
||||
@@ -51,13 +53,13 @@ export function useLocale() {
|
||||
}
|
||||
|
||||
// initialization
|
||||
function setupLocale() {
|
||||
function setLocale() {
|
||||
const lang = unref(getLang);
|
||||
lang && changeLocale(lang);
|
||||
}
|
||||
|
||||
return {
|
||||
setupLocale,
|
||||
setLocale,
|
||||
getLocale,
|
||||
getLang,
|
||||
changeLocale,
|
11
src/main.ts
11
src/main.ts
@@ -6,18 +6,19 @@ import { setupStore } from '/@/store';
|
||||
import { setupAntd } from '/@/setup/ant-design-vue';
|
||||
import { setupErrorHandle } from '/@/setup/error-handle';
|
||||
import { setupGlobDirectives } from '/@/directives';
|
||||
import { setupI18n } from '/@/setup/i18n';
|
||||
import { setupI18n } from '/@/locales/setupI18n';
|
||||
import { setupProdMockServer } from '../mock/_createProductionServer';
|
||||
import { setApp } from '/@/setup/App';
|
||||
|
||||
import { registerGlobComp } from '/@/components/registerGlobComp';
|
||||
|
||||
import { isDevMode, isProdMode, isUseMock } from '/@/utils/env';
|
||||
|
||||
import '/@/design/index.less';
|
||||
|
||||
import '/@/locales/index';
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
registerGlobComp(app);
|
||||
|
||||
// Configure component library
|
||||
setupAntd(app);
|
||||
|
||||
@@ -51,5 +52,3 @@ if (isDevMode()) {
|
||||
if (isProdMode() && isUseMock()) {
|
||||
setupProdMockServer();
|
||||
}
|
||||
// Used to share app instances in other modules
|
||||
setApp(app);
|
||||
|
@@ -1,5 +0,0 @@
|
||||
// The content here is just for type approval. The actual file content is overwritten by transform
|
||||
// For specific coverage, see build/vite/plugin/transform/dynamic-import/index.ts
|
||||
export default function (name: string) {
|
||||
return name as any;
|
||||
}
|
@@ -2,8 +2,8 @@ import type { AppRouteModule, AppRouteRecordRaw } from '/@/router/types';
|
||||
import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router';
|
||||
|
||||
import { getParentLayout, LAYOUT } from '/@/router/constant';
|
||||
import dynamicImport from './dynamicImport';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { warn } from '/@/utils/log';
|
||||
|
||||
export type LayoutMapKey = 'LAYOUT';
|
||||
|
||||
@@ -11,12 +11,20 @@ const LayoutMap = new Map<LayoutMapKey, () => Promise<typeof import('*.vue')>>()
|
||||
|
||||
// 动态引入
|
||||
function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
|
||||
// TODO Because xlsx does not support vite2.0 temporarily. So filter the excel example first
|
||||
const dynamicViewsModules = importContext({
|
||||
dir: '/@/views',
|
||||
deep: true,
|
||||
regexp: /^(?!.*\/demo\/excel).*\.(tsx?|vue)$/,
|
||||
dynamicImport: true,
|
||||
dynamicEnabled: 'autoImportRoute',
|
||||
});
|
||||
if (!routes) return;
|
||||
routes.forEach((item) => {
|
||||
const { component, name } = item;
|
||||
const { children } = item;
|
||||
if (component) {
|
||||
item.component = dynamicImport(component as string);
|
||||
item.component = dynamicImport(dynamicViewsModules, component as string);
|
||||
} else if (name) {
|
||||
item.component = getParentLayout(name);
|
||||
}
|
||||
@@ -24,6 +32,24 @@ function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
|
||||
});
|
||||
}
|
||||
|
||||
function dynamicImport(dynamicViewsModules: DynamicImportContextResult, component: string) {
|
||||
const keys = dynamicViewsModules.keys();
|
||||
const matchKeys = keys.filter((key) => {
|
||||
const k = key.substr(1);
|
||||
return k.startsWith(component) || k.startsWith(`/${component}`);
|
||||
});
|
||||
if (matchKeys?.length === 1) {
|
||||
const matchKey = matchKeys[0];
|
||||
return dynamicViewsModules(matchKey);
|
||||
}
|
||||
if (matchKeys?.length > 1) {
|
||||
warn(
|
||||
'Please do not create `.vue` and `.TSX` files with the same file name in the same hierarchical directory under the views folder. This will cause dynamic introduction failure'
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Turn background objects into routing objects
|
||||
export function transformObjToRoute<T = AppRouteModule>(routeList: AppRouteModule[]): T[] {
|
||||
LayoutMap.set('LAYOUT', LAYOUT);
|
||||
|
@@ -9,18 +9,18 @@ import router from '/@/router';
|
||||
import { PermissionModeEnum } from '/@/enums/appEnum';
|
||||
import { pathToRegexp } from 'path-to-regexp';
|
||||
|
||||
import modules from 'globby!/@/router/menus/modules/**/*.@(ts)';
|
||||
|
||||
const reg = /(((https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
|
||||
import modules from 'glob:./modules/**/*.ts';
|
||||
|
||||
const menuModules: MenuModule[] = [];
|
||||
|
||||
Object.keys(modules).forEach((key) => {
|
||||
const moduleItem = modules[key];
|
||||
const menuModule = Array.isArray(moduleItem) ? [...moduleItem] : [moduleItem];
|
||||
menuModules.push(...menuModule);
|
||||
const mod = modules[key].default || {};
|
||||
const modList = Array.isArray(mod) ? [...mod] : [mod];
|
||||
menuModules.push(...modList);
|
||||
});
|
||||
|
||||
const reg = /(((https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
|
||||
|
||||
// ===========================
|
||||
// ==========Helper===========
|
||||
// ===========================
|
||||
|
@@ -2,17 +2,18 @@ import type { AppRouteRecordRaw, AppRouteModule } from '/@/router/types';
|
||||
|
||||
import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '../constant';
|
||||
|
||||
import modules from 'globby!/@/router/routes/modules/**/*.@(ts)';
|
||||
import { mainOutRoutes } from './mainOut';
|
||||
import { PageEnum } from '/@/enums/pageEnum';
|
||||
|
||||
import { t } from '/@/hooks/web/useI18n';
|
||||
|
||||
import modules from 'glob:./modules/**/*.ts';
|
||||
|
||||
const routeModuleList: AppRouteModule[] = [];
|
||||
|
||||
Object.keys(modules).forEach((key) => {
|
||||
const mod = Array.isArray(modules[key]) ? [...modules[key]] : [modules[key]];
|
||||
routeModuleList.push(...mod);
|
||||
const mod = modules[key].default || {};
|
||||
const modList = Array.isArray(mod) ? [...mod] : [mod];
|
||||
routeModuleList.push(...modList);
|
||||
});
|
||||
|
||||
export const asyncRoutes = [PAGE_NOT_FOUND_ROUTE, ...routeModuleList];
|
||||
|
@@ -172,51 +172,51 @@ const feat: AppRouteModule = {
|
||||
title: t('routes.demo.feat.errorLog'),
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'excel',
|
||||
name: 'Excel',
|
||||
redirect: '/feat/excel/customExport',
|
||||
component: getParentLayout('Excel'),
|
||||
meta: {
|
||||
// icon: 'mdi:microsoft-excel',
|
||||
title: t('routes.demo.excel.excel'),
|
||||
},
|
||||
// {
|
||||
// path: 'excel',
|
||||
// name: 'Excel',
|
||||
// redirect: '/feat/excel/customExport',
|
||||
// component: getParentLayout('Excel'),
|
||||
// meta: {
|
||||
// // icon: 'mdi:microsoft-excel',
|
||||
// title: t('routes.demo.excel.excel'),
|
||||
// },
|
||||
|
||||
children: [
|
||||
{
|
||||
path: 'customExport',
|
||||
name: 'CustomExport',
|
||||
component: () => import('/@/views/demo/excel/CustomExport.vue'),
|
||||
meta: {
|
||||
title: t('routes.demo.excel.customExport'),
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'jsonExport',
|
||||
name: 'JsonExport',
|
||||
component: () => import('/@/views/demo/excel/JsonExport.vue'),
|
||||
meta: {
|
||||
title: t('routes.demo.excel.jsonExport'),
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'arrayExport',
|
||||
name: 'ArrayExport',
|
||||
component: () => import('/@/views/demo/excel/ArrayExport.vue'),
|
||||
meta: {
|
||||
title: t('routes.demo.excel.arrayExport'),
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'importExcel',
|
||||
name: 'ImportExcel',
|
||||
component: () => import('/@/views/demo/excel/ImportExcel.vue'),
|
||||
meta: {
|
||||
title: t('routes.demo.excel.importExcel'),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// children: [
|
||||
// {
|
||||
// path: 'customExport',
|
||||
// name: 'CustomExport',
|
||||
// component: () => import('/@/views/demo/excel/CustomExport.vue'),
|
||||
// meta: {
|
||||
// title: t('routes.demo.excel.customExport'),
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: 'jsonExport',
|
||||
// name: 'JsonExport',
|
||||
// component: () => import('/@/views/demo/excel/JsonExport.vue'),
|
||||
// meta: {
|
||||
// title: t('routes.demo.excel.jsonExport'),
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: 'arrayExport',
|
||||
// name: 'ArrayExport',
|
||||
// component: () => import('/@/views/demo/excel/ArrayExport.vue'),
|
||||
// meta: {
|
||||
// title: t('routes.demo.excel.arrayExport'),
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: 'importExcel',
|
||||
// name: 'ImportExcel',
|
||||
// component: () => import('/@/views/demo/excel/ImportExcel.vue'),
|
||||
// meta: {
|
||||
// title: t('routes.demo.excel.importExcel'),
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
path: 'testTab/:id',
|
||||
name: 'TestTab',
|
||||
|
@@ -172,7 +172,7 @@ const setting: ProjectConfig = {
|
||||
|
||||
// Whether to cancel the http request that has been sent but not responded when switching the interface.
|
||||
// If it is enabled, I want to overwrite a single interface. Can be set in a separate interface
|
||||
removeAllHttpPending: true,
|
||||
removeAllHttpPending: false,
|
||||
};
|
||||
|
||||
export default setting;
|
||||
|
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
import type { ProjectConfig } from '/@/types/config';
|
||||
import type { App } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { ThemeModeEnum } from '/@/enums/appEnum';
|
||||
@@ -21,17 +20,6 @@ import {
|
||||
import { appStore } from '/@/store/modules/app';
|
||||
import { deepMerge } from '/@/utils';
|
||||
|
||||
// Used to share global app instances
|
||||
let app: App;
|
||||
|
||||
export function setApp(_app: App): void {
|
||||
app = _app;
|
||||
}
|
||||
|
||||
export function getApp(): App {
|
||||
return app;
|
||||
}
|
||||
|
||||
// TODO Theme switching
|
||||
export function useThemeMode(mode: ThemeModeEnum) {
|
||||
const modeRef = ref(mode);
|
||||
|
78
src/types/vue-app-env.d.ts
vendored
78
src/types/vue-app-env.d.ts
vendored
@@ -23,81 +23,3 @@ declare namespace NodeJS {
|
||||
}
|
||||
|
||||
declare let process: NodeJS.Process;
|
||||
|
||||
declare module '*.bmp' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.gif' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.jpg' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.jpeg' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.png' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.webp' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.svg' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.json' {
|
||||
const content: any | any[];
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module '*.scss' {
|
||||
const content: {
|
||||
readonly [className: string]: string;
|
||||
};
|
||||
export default content;
|
||||
}
|
||||
declare module '*.less' {
|
||||
const content: {
|
||||
readonly [className: string]: string;
|
||||
};
|
||||
export default content;
|
||||
}
|
||||
declare module '*.styl' {
|
||||
const content: {
|
||||
readonly [className: string]: string;
|
||||
};
|
||||
export default content;
|
||||
}
|
||||
declare module '*.css' {
|
||||
const content: any;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module '*.module.css' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
||||
declare module '*.module.scss' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
||||
declare module '*.module.sass' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
1
src/types/window.d.ts
vendored
1
src/types/window.d.ts
vendored
@@ -4,5 +4,6 @@ declare global {
|
||||
declare interface Window {
|
||||
// Global vue app instance
|
||||
__APP__: App<Element>;
|
||||
__VERSION__: string;
|
||||
}
|
||||
}
|
||||
|
@@ -41,8 +41,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../../design/index.less';
|
||||
|
||||
.grow-card {
|
||||
display: flex;
|
||||
width: calc(100% - 12px);
|
||||
|
@@ -68,8 +68,6 @@
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../design/index.less';
|
||||
|
||||
.analysis {
|
||||
width: 100%;
|
||||
|
||||
|
@@ -1,5 +1,3 @@
|
||||
@import (reference) '../../../design/index.less';
|
||||
|
||||
.house-wrap {
|
||||
position: relative;
|
||||
width: 600px;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user