Compare commits
No commits in common. "0587b8ddd876fbf4956eb8d24317727381597f9e" and "b32093a9b0d6031ffb1e8bfdb4ebf13fcc71c603" have entirely different histories.
0587b8ddd8
...
b32093a9b0
|
@ -33,7 +33,6 @@ export const buildEnv = (): BuildOptions => {
|
|||
rollupOptions: {
|
||||
external: ['md-editor-v3', 'echarts'],
|
||||
input: {
|
||||
// @ts-ignore
|
||||
index: pathResolve('../index.html', import.meta.url),
|
||||
},
|
||||
// 静态资源分类打包
|
||||
|
|
14
build/css.ts
14
build/css.ts
|
@ -1,18 +1,12 @@
|
|||
import type { AcceptedPlugin } from 'postcss';
|
||||
import postCssPxToViewport8plugin from 'postcss-px-to-viewport-8-plugin';
|
||||
import type { CSSOptions } from 'vite';
|
||||
import type { CSSOptions, Plugin } from 'vite';
|
||||
|
||||
import { wrapperEnv } from './utils';
|
||||
|
||||
export const css = (mode: string): CSSOptions => {
|
||||
const plugins: AcceptedPlugin[] = [usePostCssPxToViewport8plugin(mode)];
|
||||
export const css = (mode): CSSOptions => {
|
||||
const plugins: Plugin[] = [usePostCssPxToViewport8plugin(mode)];
|
||||
|
||||
return {
|
||||
preprocessorOptions: {
|
||||
scss: {
|
||||
additionalData: `@use "@/assets/styles/minix/sidebar" as *;`,
|
||||
},
|
||||
},
|
||||
postcss: {
|
||||
plugins: plugins.filter(Boolean),
|
||||
},
|
||||
|
@ -20,7 +14,7 @@ export const css = (mode: string): CSSOptions => {
|
|||
};
|
||||
|
||||
/** 是否启用px转换vw插件 */
|
||||
const usePostCssPxToViewport8plugin = (mode: string): AcceptedPlugin => {
|
||||
const usePostCssPxToViewport8plugin = (mode): Plugin => {
|
||||
const { VITE_POST_CSS_PX_TO_VIEWPORT8_PLUGIN } = wrapperEnv(mode, 'VITE');
|
||||
|
||||
const cssPxToVw = postCssPxToViewport8plugin({
|
||||
|
|
|
@ -3,7 +3,7 @@ import dayjs, { type Dayjs } from 'dayjs';
|
|||
import duration from 'dayjs/plugin/duration';
|
||||
import gradientString from 'gradient-string';
|
||||
|
||||
import { logOutputSize, wrapperEnv } from './utils';
|
||||
import { wrapperEnv } from './utils';
|
||||
|
||||
dayjs.extend(duration);
|
||||
|
||||
|
@ -17,12 +17,13 @@ const boxenOptions: BoxenOptions = {
|
|||
/* 输出日志信息 */
|
||||
const printLogMessage = (VITE_PORT: number) => {
|
||||
return gradientString('cyan', 'magenta').multiline(
|
||||
`欢迎使用此项目,项目访问地址如下:
|
||||
`保存成功!服务器重新启动...
|
||||
项目访问地址如下:
|
||||
http://localhost:${VITE_PORT}`
|
||||
);
|
||||
};
|
||||
|
||||
export const viteConsoleLog = (mode: string) => {
|
||||
export const viteConsoleLog = (mode) => {
|
||||
const { VITE_PORT } = wrapperEnv(mode);
|
||||
|
||||
let config: { command: string };
|
||||
|
@ -43,12 +44,9 @@ export const viteConsoleLog = (mode: string) => {
|
|||
if (config.command === 'build') {
|
||||
endTime = dayjs(new Date());
|
||||
const format = dayjs.duration(endTime.diff(startTime)).format('mm分ss秒');
|
||||
|
||||
console.log(
|
||||
boxen(
|
||||
gradientString('cyan', 'magenta').multiline(
|
||||
`🎉 恭喜打包完成(总用时${format})打包大小(${logOutputSize()})`
|
||||
),
|
||||
gradientString('cyan', 'magenta').multiline(`🎉 恭喜打包完成(总用时${format})`),
|
||||
boxenOptions
|
||||
)
|
||||
);
|
||||
|
|
|
@ -9,6 +9,6 @@ const include = ['vue', 'vue-router', 'dayjs', 'axios', 'pinia', 'vue-types', 'j
|
|||
/**
|
||||
* 在预构建中强制排除的依赖项
|
||||
*/
|
||||
const exclude: string[] = [];
|
||||
const exclude = [];
|
||||
|
||||
export { include, exclude };
|
||||
|
|
|
@ -1,26 +1,24 @@
|
|||
import UnoCssIcons from '@unocss/preset-icons';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx';
|
||||
import { presetIcons } from 'unocss';
|
||||
import { presetIcons, presetUno } from 'unocss';
|
||||
import UnoCSS from 'unocss/vite';
|
||||
import type { PluginOption } from 'vite';
|
||||
import { vitePluginFakeServer } from 'vite-plugin-fake-server';
|
||||
import removeConsole from 'vite-plugin-remove-console';
|
||||
import vueDevTools from 'vite-plugin-vue-devtools';
|
||||
import Inspector from 'vite-plugin-vue-inspector';
|
||||
|
||||
import { useCDN } from './cdn';
|
||||
import { viteConsoleLog } from './info';
|
||||
import { compressPack, report, wrapperEnv } from './utils';
|
||||
|
||||
export const plugins = (mode: string): PluginOption[] => {
|
||||
export const plugins = (mode): PluginOption[] => {
|
||||
return [
|
||||
vue(),
|
||||
vueJsx(),
|
||||
Inspector(),
|
||||
report(),
|
||||
removeConsole(),
|
||||
vueDevTools(),
|
||||
useCDN(mode),
|
||||
viteConsoleLog(mode),
|
||||
UnoCSS({
|
||||
|
@ -28,19 +26,18 @@ export const plugins = (mode: string): PluginOption[] => {
|
|||
inspector: true, // 控制台是否打印 UnoCSS inspector
|
||||
presets: [
|
||||
presetIcons({
|
||||
prefix: '',
|
||||
extraProperties: {
|
||||
display: 'inline-block',
|
||||
'vertical-align': 'middle',
|
||||
},
|
||||
}),
|
||||
UnoCssIcons({
|
||||
prefix: '',
|
||||
prefix: 'i-',
|
||||
extraProperties: {
|
||||
display: 'inline-block',
|
||||
'vertical-align': 'middle',
|
||||
},
|
||||
}),
|
||||
presetUno(),
|
||||
],
|
||||
}),
|
||||
compressPack(mode),
|
||||
|
@ -49,7 +46,7 @@ export const plugins = (mode: string): PluginOption[] => {
|
|||
};
|
||||
|
||||
/** MOCK 服务 */
|
||||
const useMock = (mode: string) => {
|
||||
const useMock = (mode) => {
|
||||
const { VITE_MOCK_DEV_SERVER } = wrapperEnv(mode);
|
||||
|
||||
return VITE_MOCK_DEV_SERVER
|
||||
|
|
|
@ -4,7 +4,7 @@ export const resolve = () => {
|
|||
return {
|
||||
alias: {
|
||||
'@': pathResolve('../src'),
|
||||
// '@build': pathResolve(),
|
||||
'@build': pathResolve(),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ import type { ServerOptions } from 'vite';
|
|||
import { wrapperEnv } from './utils';
|
||||
|
||||
/* 开发服务配置 */
|
||||
export const server = (mode: string) => {
|
||||
export const server = (mode) => {
|
||||
const { VITE_PORT, VITE_APP_URL, VITE_STRICT_PORT } = wrapperEnv(mode);
|
||||
|
||||
const options: ServerOptions = {
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
import { dirname, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { visualizer } from 'rollup-plugin-visualizer';
|
||||
import { loadEnv } from 'vite';
|
||||
import viteCompression from 'vite-plugin-compression';
|
||||
|
||||
import { buildEnv } from './buildEnv';
|
||||
|
||||
export const root: string = process.cwd();
|
||||
|
||||
/**
|
||||
|
@ -16,7 +12,6 @@ export const root: string = process.cwd();
|
|||
* @param dir 路径片段,默认`build`
|
||||
* @param metaUrl 模块的完整`url`,如果在`build`目录外调用必传`import.meta.url`
|
||||
*/
|
||||
// @ts-ignore
|
||||
export const pathResolve = (dir = '.', metaUrl = import.meta.url) => {
|
||||
// 当前文件目录的绝对路径
|
||||
const currentFileDir = dirname(fileURLToPath(metaUrl));
|
||||
|
@ -39,20 +34,18 @@ export const pathResolve = (dir = '.', metaUrl = import.meta.url) => {
|
|||
* @param prefix 需要过滤的前缀
|
||||
* @link 参考:https://cn.vite.dev/config/#using-environment-variables-in-config
|
||||
*/
|
||||
// @ts-ignore
|
||||
export const wrapperEnv = (mode: string, prefix: string = ''): ViteEnv => {
|
||||
const env: any = loadEnv(mode, root, prefix);
|
||||
export const wrapperEnv = (mode, prefix: string = ''): ViteEnv => {
|
||||
const env = loadEnv(mode, root, prefix);
|
||||
|
||||
// 将变量转换指定类型
|
||||
for (const envName of Object.keys(env)) {
|
||||
let realName: string | boolean | number = env[envName].replace(/\\n/g, '\n');
|
||||
let realName = env[envName].replace(/\\n/g, '\n');
|
||||
realName = realName === 'true' ? true : realName === 'false' ? false : realName;
|
||||
|
||||
if (envName === 'VITE_PORT') {
|
||||
realName = Number(realName);
|
||||
}
|
||||
env[envName] = realName;
|
||||
// @ts-ignore
|
||||
process.env[envName] = realName;
|
||||
}
|
||||
return env;
|
||||
|
@ -67,52 +60,8 @@ export const report = () => {
|
|||
};
|
||||
|
||||
/* 启用gzip压缩 */
|
||||
export const compressPack = (mode: string) => {
|
||||
export const compressPack = (mode) => {
|
||||
const { VITE_COMPRESSION } = wrapperEnv(mode);
|
||||
|
||||
return VITE_COMPRESSION == 'gzip' ? viteCompression({ threshold: 1024000 }) : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* 计算打包后文件夹大小
|
||||
* @returns
|
||||
*/
|
||||
export const logOutputSize = (): string => {
|
||||
const outDir = `../${buildEnv().outDir}`;
|
||||
|
||||
function convertSize(size: number) {
|
||||
const units: Array<string> = ['byte', 'KB', 'MB', 'GB'];
|
||||
|
||||
// 输入的单位是否存在
|
||||
let index = 0;
|
||||
|
||||
while (size >= 1024) {
|
||||
size /= 1024;
|
||||
index++;
|
||||
}
|
||||
|
||||
return `${size.toFixed(2)} ${units[index]}`;
|
||||
}
|
||||
|
||||
// 计算文件夹字节大小
|
||||
function getFolderSize(folderPath: string) {
|
||||
let size = 0;
|
||||
|
||||
fs.readdirSync(folderPath).forEach((fileName: string) => {
|
||||
const filePath = path.join(folderPath, fileName);
|
||||
const stats = fs.statSync(filePath);
|
||||
|
||||
if (stats.isFile()) {
|
||||
size += stats.size;
|
||||
} else if (stats.isDirectory()) {
|
||||
size += getFolderSize(filePath);
|
||||
}
|
||||
});
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
const folderSize = getFolderSize(path.resolve(__dirname, outDir));
|
||||
|
||||
return convertSize(folderSize);
|
||||
};
|
||||
|
|
20
package.json
20
package.json
|
@ -1,39 +1,29 @@
|
|||
{
|
||||
"name": "screen-template",
|
||||
"name": "dashboard-template",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"author": {
|
||||
"name": "Bunny",
|
||||
"url": "https://github.com/BunnyMaster"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"report": "rimraf dist && vite build",
|
||||
"lint:eslint": "eslint --cache --max-warnings 0 \"{src,mock,build}/**/*.{vue,js,ts,tsx}\" --fix",
|
||||
"lint:prettier": "prettier --write \"src/**/*.{js,ts,json,tsx,css,scss,vue,html,md}\"",
|
||||
"lint:stylelint": "stylelint --cache --fix \"**/*.{html,vue,css,scss}\" --cache-location node_modules/.cache/stylelint/",
|
||||
"lint": "pnpm lint:eslint && pnpm lint:prettier && pnpm lint:stylelint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@eslint/js": "^9.21.0",
|
||||
"@parcel/watcher": "^2.5.1",
|
||||
"@types/node": "^22.13.10",
|
||||
"@typescript-eslint/eslint-plugin": "^8.24.1",
|
||||
"@typescript-eslint/parser": "^8.24.1",
|
||||
"@unocss/preset-icons": "^66.0.0",
|
||||
"@unocss/reset": "^66.0.0",
|
||||
"@vitejs/plugin-vue-jsx": "^4.1.1",
|
||||
"@vueuse/core": "^12.8.2",
|
||||
"animate.css": "^4.1.1",
|
||||
"autofit.js": "^3.2.4",
|
||||
"axios": "^1.7.9",
|
||||
"boxen": "^8.0.1",
|
||||
"dayjs": "^1.11.13",
|
||||
"echarts": "^5.6.0",
|
||||
"esbuild": "^0.25.1",
|
||||
"eslint": "^9.9.1",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-define-config": "^2.1.0",
|
||||
|
@ -45,7 +35,6 @@
|
|||
"nprogress": "^0.2.0",
|
||||
"pinia": "^2.3.1",
|
||||
"pinia-plugin-persistedstate": "^3.2.3",
|
||||
"postcss": "^8.5.3",
|
||||
"postcss-px-to-viewport-8-plugin": "^1.2.5",
|
||||
"prettier": "^3.3.3",
|
||||
"qs": "^6.14.0",
|
||||
|
@ -64,24 +53,19 @@
|
|||
"vite-plugin-remove-console": "^2.2.0",
|
||||
"vite-plugin-vue-inspector": "^5.3.1",
|
||||
"vue": "^3.5.13",
|
||||
"vue-demi": "^0.14.10",
|
||||
"vue-eslint-parser": "^9.4.3",
|
||||
"vue-router": "^4.4.3",
|
||||
"vue-types": "^6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify/json": "^2.2.310",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@types/qs": "^6.9.18",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||
"typescript": "~5.7.2",
|
||||
"vite": "^6.1.0",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vue-tsc": "^2.2.0",
|
||||
"vite-plugin-vue-devtools": "^7.7.2",
|
||||
"jiti": "^2.4.2"
|
||||
"vue-tsc": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0",
|
||||
|
|
764
pnpm-lock.yaml
764
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
5
push.sh
5
push.sh
|
@ -1,5 +0,0 @@
|
|||
git checkout master
|
||||
git merge dev
|
||||
git push --all
|
||||
git push --tags
|
||||
git checkout dev
|
23
src/App.vue
23
src/App.vue
|
@ -1,28 +1,7 @@
|
|||
<template>
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<transition
|
||||
:enter-active-class="
|
||||
route.meta.transition?.enter
|
||||
? `animate__animated ${route.meta.transition.enter}`
|
||||
: 'animate__animated animate__fadeInLeft animate__faster'
|
||||
"
|
||||
:leave-active-class="
|
||||
route.meta.transition?.leave
|
||||
? `animate__animated ${route.meta.transition.leave}`
|
||||
: 'animate__animated animate__fadeOutLeft animate__faster'
|
||||
"
|
||||
mode="out-in"
|
||||
>
|
||||
<transition :name="route.meta.transition || 'fade-transform'" mode="out-in">
|
||||
<component :is="Component" :key="route.path" />
|
||||
</transition>
|
||||
</router-view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup></script>
|
||||
<style lang="scss">
|
||||
#app {
|
||||
width: 100%;
|
||||
//height: 1080px;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -44,7 +44,7 @@ service.interceptors.response.use(
|
|||
}
|
||||
|
||||
// ElMessage.error(msg || '系统出错');
|
||||
return Promise.reject(response.data.message || 'Error');
|
||||
return Promise.reject(msg || 'Error');
|
||||
},
|
||||
(error: any) => {
|
||||
// 异常处理
|
||||
|
|
|
@ -44,7 +44,7 @@ service.interceptors.response.use(
|
|||
}
|
||||
|
||||
// ElMessage.error(msg || '系统出错');
|
||||
return Promise.reject(response.data.message || 'Error');
|
||||
return Promise.reject(msg || 'Error');
|
||||
},
|
||||
(error: any) => {
|
||||
// 异常处理
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
@mixin view-style-default($sidebar-width,$content-width) {
|
||||
&__sidebar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: $sidebar-width;
|
||||
height: 100%;
|
||||
color: #fff;
|
||||
|
||||
&-item {
|
||||
padding: 9px 15px;
|
||||
width: 100%;
|
||||
background: rgba(14, 95, 255, 0.2);
|
||||
}
|
||||
|
||||
&-tag {
|
||||
float: left;
|
||||
margin: 0 7px 0 0;
|
||||
width: 62px;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
background: rgba(24, 69, 135, 0.55);
|
||||
color: #fff;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
&-title {
|
||||
width: 172px;
|
||||
height: 42px;
|
||||
font-size: 22px;
|
||||
color: #fff;
|
||||
background: url('@/assets/images/business-supervision/bg/sidebar/bg-frame-4.png') no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
&-title-describe {
|
||||
font-size: 12px;
|
||||
color: var(--color-info-secondary-1);
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
width: $content-width;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@ import 'animate.css';
|
|||
import '@unocss/reset/tailwind-compat.css';
|
||||
import 'uno.css';
|
||||
import 'virtual:unocss-devtools';
|
||||
import '@/assets/styles/global.scss';
|
||||
|
||||
import { createApp } from 'vue';
|
||||
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
import 'dayjs/locale/zh-cn';
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
import localeData from 'dayjs/plugin/localeData';
|
||||
import weekday from 'dayjs/plugin/weekday';
|
||||
|
||||
dayjs.extend(weekday);
|
||||
dayjs.extend(localeData);
|
||||
|
||||
dayjs.locale('zh-cn');
|
||||
|
||||
export default dayjs;
|
|
@ -1,4 +1,4 @@
|
|||
import { BarChart, GaugeChart, LineChart, PictorialBarChart, PieChart } from 'echarts/charts';
|
||||
import { BarChart, LineChart, PieChart } from 'echarts/charts';
|
||||
import {
|
||||
DataZoomComponent,
|
||||
GraphicComponent,
|
||||
|
@ -15,6 +15,7 @@ import { CanvasRenderer, SVGRenderer } from 'echarts/renderers';
|
|||
import type { App } from 'vue';
|
||||
|
||||
const { use } = echarts;
|
||||
|
||||
use([
|
||||
PieChart,
|
||||
BarChart,
|
||||
|
@ -30,8 +31,6 @@ use([
|
|||
TooltipComponent,
|
||||
DataZoomComponent,
|
||||
VisualMapComponent,
|
||||
PictorialBarChart,
|
||||
GaugeChart,
|
||||
]);
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,20 +3,19 @@ import type { App } from 'vue';
|
|||
import { setupDirective } from '@/directive';
|
||||
import { autoFit } from '@/plugins/autofit';
|
||||
import { useEcharts } from '@/plugins/echarts';
|
||||
import { setupRouter } from '@/router';
|
||||
import { setUpRouter } from '@/router';
|
||||
import { setupStore } from '@/store';
|
||||
|
||||
export default {
|
||||
install(app: App<Element>) {
|
||||
// 设置路由
|
||||
setupRouter(app);
|
||||
setUpRouter(app);
|
||||
// 设置状态管理
|
||||
setupStore(app);
|
||||
// 设置指令
|
||||
setupDirective(app);
|
||||
// 根据需求引入echarts
|
||||
useEcharts(app);
|
||||
// 使用autoFit,在环境配置文件中设置
|
||||
autoFit();
|
||||
},
|
||||
};
|
||||
|
|
|
@ -6,15 +6,15 @@ import home from '@/router/modules/home';
|
|||
import remaining from '@/router/modules/remaining';
|
||||
|
||||
// 静态路由
|
||||
const routes: RouteRecordRaw[] = [...remaining, ...home, ...error] as RouteRecordRaw[];
|
||||
const routes: RouteRecordRaw[] = [...remaining, ...home, ...error];
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes,
|
||||
scrollBehavior: () => ({ left: 0, top: 0, behavior: 'smooth' }),
|
||||
scrollBehavior: () => ({ x: 0, y: 0 }),
|
||||
});
|
||||
|
||||
/** 全局注册 router */
|
||||
export const setupRouter = (app: App<Element>) => {
|
||||
export const setUpRouter = (app: App<Element>) => {
|
||||
app.use(router);
|
||||
};
|
||||
|
||||
|
@ -23,10 +23,4 @@ export const resetRouter = () => {
|
|||
router.replace({ path: '/' }).then();
|
||||
};
|
||||
|
||||
// router.afterEach((to, from) => {
|
||||
// const toDepth = to.path.split('/').length;
|
||||
// const fromDepth = from.path.split('/').length;
|
||||
// to.meta.transition = toDepth < fromDepth ? 'slide-right' : 'slide-left';
|
||||
// });
|
||||
|
||||
export default router;
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import type { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
import type { RouteConfigsTable } from '@/types/router/Route';
|
||||
|
||||
const routes: RouteRecordRaw[] | RouteConfigsTable[] = [
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/error',
|
||||
component: () => import('@/views/error-page/404.vue'),
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import type { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
import Layout from '@/layout/index.vue';
|
||||
import type { RouteConfigsTable } from '@/types/router/Route';
|
||||
|
||||
const routes: RouteRecordRaw[] | RouteConfigsTable[] = [
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/',
|
||||
name: '/',
|
||||
component: Layout,
|
||||
meta: { transition: 'fade' },
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import type { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
import Layout from '@/layout/index.vue';
|
||||
import type { RouteConfigsTable } from '@/types/router/Route';
|
||||
|
||||
const routes: RouteRecordRaw[] | RouteConfigsTable[] = [
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/redirect',
|
||||
component: Layout,
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
import { defineStore } from 'pinia';
|
||||
|
||||
import { isCSSColor, isPath } from '@/utils/regexp/regexpBackground';
|
||||
|
||||
const useAppStore = defineStore('appStore', {
|
||||
state() {
|
||||
return {
|
||||
background: '',
|
||||
};
|
||||
},
|
||||
getters: {},
|
||||
actions: {
|
||||
setBackground(background: string) {
|
||||
if (isCSSColor(background)) {
|
||||
this.background = background;
|
||||
} else if (isPath(background)) {
|
||||
const href = new URL(background, import.meta.url).href;
|
||||
this.background = `url(${href})`;
|
||||
} else {
|
||||
const href = new URL('@/assets/images/common/bg/bg-layout.png', import.meta.url).href;
|
||||
this.background = `url(${href})`;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export { useAppStore };
|
|
@ -1,11 +0,0 @@
|
|||
// types/router.d.ts
|
||||
import 'vue-router';
|
||||
|
||||
declare module 'vue-router' {
|
||||
interface RouteMeta {
|
||||
transition?: {
|
||||
enter: string;
|
||||
leave: string;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
import type { RouteComponent } from 'vue-router';
|
||||
|
||||
/**
|
||||
* @description 动画入场和离场
|
||||
*/
|
||||
interface Transition {
|
||||
enter?: string;
|
||||
leave?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 完整子路由的`meta`配置表
|
||||
*/
|
||||
interface CustomizeRouteMeta {
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
transition?: Transition;
|
||||
hidden?: boolean;
|
||||
/* 头部类型 */
|
||||
headerType?: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 整体路由配置表(包括完整子路由)
|
||||
*/
|
||||
export interface RouteConfigsTable {
|
||||
/** 路由地址 `必填` */
|
||||
path: string;
|
||||
/** 路由名字(保持唯一)`可选` */
|
||||
name?: string;
|
||||
/** `Layout`组件 `可选` */
|
||||
component?: RouteComponent;
|
||||
/** 路由重定向 `可选` */
|
||||
redirect?: string;
|
||||
meta?: CustomizeRouteMeta;
|
||||
/** 子路由配置项 */
|
||||
children?: Array<RouteConfigsTable>;
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
import { useDebounceFn, useEventListener } from '@vueuse/core';
|
||||
|
||||
import echarts from '@/plugins/echarts';
|
||||
|
||||
/** 通用重置图表样式 */
|
||||
export const debounceChart = (myChart: echarts.ECharts | undefined) => {
|
||||
const debounceFn = useDebounceFn(() => {
|
||||
myChart!.resize();
|
||||
}, 500);
|
||||
|
||||
useEventListener(window, 'resize', debounceFn);
|
||||
};
|
||||
|
||||
/** 数字格式化 */
|
||||
export const formatter = (number: any) => {
|
||||
const numbers = number.toString().split('').reverse();
|
||||
const segs = [];
|
||||
|
||||
while (numbers.length) segs.push(numbers.splice(0, 3).join(''));
|
||||
|
||||
return segs.join(',').split('').reverse().join('');
|
||||
};
|
||||
|
||||
/** 颜色渲染 */
|
||||
export const graphicLinearGradient = (
|
||||
color1: string,
|
||||
color2: string,
|
||||
coordinate: Array<number> = [0, 0, 0, 1]
|
||||
) => {
|
||||
return new echarts.graphic.LinearGradient(
|
||||
coordinate[0],
|
||||
coordinate[1],
|
||||
coordinate[2],
|
||||
coordinate[3],
|
||||
[
|
||||
{ offset: 0, color: color1 },
|
||||
{ offset: 1, color: color2 },
|
||||
]
|
||||
);
|
||||
};
|
|
@ -1,24 +0,0 @@
|
|||
/**
|
||||
* 复制到剪切板
|
||||
* @param text 文本内容
|
||||
*/
|
||||
export const copy = (text: string) => {
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.value = text;
|
||||
textarea.style.position = 'fixed';
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
|
||||
try {
|
||||
const success = document.execCommand('copy');
|
||||
if (success) {
|
||||
(window as any as any).$message.success('复制成功!');
|
||||
} else {
|
||||
(window as any).$message.success('复制失败!');
|
||||
}
|
||||
} catch (err: any) {
|
||||
(window as any).$message.success('复制失败!请手动复制');
|
||||
} finally {
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
};
|
|
@ -1,45 +0,0 @@
|
|||
export function downloadTextAsFile(text: string, filename: string) {
|
||||
// 直接创建 File 对象(比 Blob 更高级)
|
||||
const file = new File([text], filename, { type: 'text/plain' });
|
||||
|
||||
// 创建下载链接
|
||||
const url = URL.createObjectURL(file);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
|
||||
// 触发下载
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
|
||||
// 清理
|
||||
requestIdleCallback(() => {
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(a.href);
|
||||
});
|
||||
}
|
||||
|
||||
export const downloadBlob = (response: any) => {
|
||||
try {
|
||||
// 从响应头获取文件名
|
||||
const contentDisposition = response.headers['content-disposition'];
|
||||
let fileName = 'download.zip';
|
||||
if (contentDisposition) {
|
||||
const fileNameMatch = contentDisposition.match(/filename="?(.+)"/);
|
||||
if (fileNameMatch && fileNameMatch[1]) {
|
||||
fileName = fileNameMatch[1];
|
||||
}
|
||||
}
|
||||
|
||||
const url = window.URL.createObjectURL(new Blob([response.data]));
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.setAttribute('download', fileName);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
link.remove();
|
||||
window.URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
|
@ -1,29 +0,0 @@
|
|||
/** 判断是否是CSS颜色 */
|
||||
function isCSSColor(str: string) {
|
||||
// 匹配十六进制颜色(如 #fff, #ffffff)
|
||||
const hexColor = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
|
||||
|
||||
// 匹配RGB/RGBA颜色(如 rgb(255, 255, 255), rgba(255, 255, 255, 0.5))
|
||||
const rgbColor = /^rgba?\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*(,\s*[\d\.]+)?\s*\)$/;
|
||||
|
||||
// 匹配HSL/HSLA颜色(如 hsl(120, 100%, 50%), hsla(120, 100%, 50%, 0.5))
|
||||
const hslColor = /^hsla?\(\s*\d{1,3}\s*,\s*\d{1,3}%\s*,\s*\d{1,3}%\s*(,\s*[\d\.]+)?\s*\)$/;
|
||||
|
||||
// 匹配预定义颜色名称(如 red, blue, green)
|
||||
const namedColor = /^[a-zA-Z]+$/;
|
||||
|
||||
return hexColor.test(str) || rgbColor.test(str) || hslColor.test(str) || namedColor.test(str);
|
||||
}
|
||||
|
||||
/** 判断是否是相对路径或绝对路径 */
|
||||
function isPath(str: string) {
|
||||
// 匹配相对路径(如 ./path, ../path, path/to/file)
|
||||
const relativePath = /^\.{0,2}\/[^\/].*$/;
|
||||
|
||||
// 匹配绝对路径(如 /path/to/file, C:\path\to\file)
|
||||
const absolutePath = /^(?:\/|[A-Za-z]:\\).*$/;
|
||||
|
||||
return relativePath.test(str) || absolutePath.test(str);
|
||||
}
|
||||
|
||||
export { isCSSColor, isPath };
|
|
@ -1,49 +1,49 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"strict": false,
|
||||
"jsx": "preserve",
|
||||
"importHelpers": true,
|
||||
"experimentalDecorators": true,
|
||||
"strictFunctionTypes": false,
|
||||
"skipLibCheck": true,
|
||||
"target": "esnext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"strict": true,
|
||||
"noLib": false,
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"isolatedModules": true,
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom"
|
||||
],
|
||||
"baseUrl": ".",
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"sourceMap": true,
|
||||
"baseUrl": ".",
|
||||
"allowJs": false,
|
||||
"resolveJsonModule": true,
|
||||
"lib": [
|
||||
"ESNext",
|
||||
"DOM"
|
||||
],
|
||||
"jsx": "preserve",
|
||||
"jsxFactory": "h",
|
||||
"jsxFragmentFactory": "Fragment",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
],
|
||||
"@build/*": [
|
||||
"build/*"
|
||||
]
|
||||
},
|
||||
"types": [
|
||||
"node",
|
||||
"vite/client"
|
||||
"vite/client",
|
||||
"unplugin-icons/types/vue",
|
||||
"element-plus/global"
|
||||
]
|
||||
},
|
||||
"files": [],
|
||||
"include": [
|
||||
"mock/*.ts",
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue",
|
||||
"vite.config.ts",
|
||||
"src/**/*.d.ts"
|
||||
"src/types/*.d.ts",
|
||||
"vite.config.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"dist",
|
||||
"**/*.js",
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -10,8 +10,7 @@ import { server } from './build/server';
|
|||
import { root, wrapperEnv } from './build/utils';
|
||||
|
||||
// https://vite.dev/config/
|
||||
// export default defineConfig(({ command, mode, isSsrBuild, isPreview }) => {
|
||||
export default defineConfig(({ mode }) => {
|
||||
export default defineConfig(({ command, mode, isSsrBuild, isPreview }) => {
|
||||
const env = wrapperEnv(mode, 'VITE');
|
||||
|
||||
return {
|
||||
|
|
Loading…
Reference in New Issue