diff --git a/.env b/.env index db9e66f..e381b3c 100644 --- a/.env +++ b/.env @@ -1,5 +1,5 @@ # 应用名称 -VITE_APP_TITLE="车辆监控中心" +VITE_APP_TITLE="Vite 模板" # 平台本地运行端口号 VITE_PORT=7000 @@ -13,6 +13,9 @@ VITE_APP_URL=http://localhost:8801 # 如果端口被占用会直接退出,而不是尝试下一个端口 VITE_STRICT_PORT=false +# 是否启用屏幕转vw适配 +VITE_POST_CSS_PX_TO_VIEWPORT8_PLUGIN=true + # 是否在打包时使用cdn替换本地库 替换 true 不替换 false VITE_CDN=false diff --git a/.env.development b/.env.development index d8b465e..5f2f00e 100644 --- a/.env.development +++ b/.env.development @@ -10,6 +10,9 @@ VITE_APP_URL=http://localhost:8801 # 如果端口被占用会直接退出,而不是尝试下一个端口 VITE_STRICT_PORT=false +# 是否启用屏幕转vw适配 +VITE_POST_CSS_PX_TO_VIEWPORT8_PLUGIN=true + # 是否在打包时使用cdn替换本地库 替换 true 不替换 false VITE_CDN=false diff --git a/.env.production b/.env.production index 0ed6804..fdb1aeb 100644 --- a/.env.production +++ b/.env.production @@ -10,6 +10,9 @@ VITE_APP_URL=http://localhost:8000 # 如果端口被占用会直接退出,而不是尝试下一个端口 VITE_STRICT_PORT=false +# 是否启用屏幕转vw适配 +VITE_POST_CSS_PX_TO_VIEWPORT8_PLUGIN=true + # 是否在打包时使用cdn替换本地库 替换 true 不替换 false VITE_CDN=false diff --git a/.prettierrc.js b/.prettierrc.js index 1bc4c23..236e742 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,14 +1,14 @@ export default { // (x)=>{},单个参数箭头函数是否显示小括号。(always:始终显示;avoid:省略括号。默认:always) - arrowParens: "always", + arrowParens: 'always', // 开始标签的右尖括号是否跟随在最后一行属性末尾,默认false bracketSameLine: false, // 对象字面量的括号之间打印空格 (true - Example: { foo: bar } ; false - Example: {foo:bar}) bracketSpacing: true, // 是否格式化一些文件中被嵌入的代码片段的风格(auto|off;默认auto) - embeddedLanguageFormatting: "auto", + embeddedLanguageFormatting: 'auto', // 指定 HTML 文件的空格敏感度 (css|strict|ignore;默认css) - htmlWhitespaceSensitivity: "ignore", + htmlWhitespaceSensitivity: 'ignore', // 当文件已经被 Prettier 格式化之后,是否会在文件顶部插入一个特殊的 @format 标记,默认false insertPragma: false, // 在 JSX 中使用单引号替代双引号,默认false @@ -16,30 +16,30 @@ export default { // 每行最多字符数量,超出换行(默认100) printWidth: 100, // 超出打印宽度 (always | never | preserve ) - proseWrap: "preserve", + proseWrap: 'preserve', // 对象属性是否使用引号(as-needed | consistent | preserve;默认as-needed:对象的属性需要加引号才添加;) - quoteProps: "as-needed", + quoteProps: 'as-needed', // 是否只格式化在文件顶部包含特定注释(@prettier| @format)的文件,默认false requirePragma: false, // 结尾添加分号 semi: true, // 使用单引号 (true:单引号;false:双引号) - singleQuote: false, + singleQuote: true, // 缩进空格数,默认2个空格 tabWidth: 2, // 元素末尾是否加逗号,默认es5: ES5中的 objects, arrays 等会添加逗号,TypeScript 中的 type 后不加逗号 - trailingComma: "es5", + trailingComma: 'es5', // 指定缩进方式,空格或tab,默认false,即使用空格 useTabs: false, - // vue 文件中是否缩进 diff --git a/src/layout/components/AppMain/MainLeft.vue b/src/layout/components/AppMain/MainLeft.vue new file mode 100644 index 0000000..4f301d4 --- /dev/null +++ b/src/layout/components/AppMain/MainLeft.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/src/layout/components/AppMain/MainRight.vue b/src/layout/components/AppMain/MainRight.vue new file mode 100644 index 0000000..1cc23a8 --- /dev/null +++ b/src/layout/components/AppMain/MainRight.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/src/layout/components/AppMain/index.vue b/src/layout/components/AppMain/index.vue index 3d94f54..d57ef21 100644 --- a/src/layout/components/AppMain/index.vue +++ b/src/layout/components/AppMain/index.vue @@ -1,38 +1,36 @@ - + diff --git a/src/layout/components/Footer/index.vue b/src/layout/components/Footer/index.vue index 975b54b..9a9b03e 100644 --- a/src/layout/components/Footer/index.vue +++ b/src/layout/components/Footer/index.vue @@ -8,8 +8,8 @@ :key="index" class="rectangle w-[138px] h-[125px] flex-y-center bg-[#0E094D55]" > - 车辆管理 - 车辆管理 + 车辆管理 + 车辆管理 diff --git a/src/layout/components/NavBar/index.vue b/src/layout/components/NavBar/index.vue index e257420..8afe163 100644 --- a/src/layout/components/NavBar/index.vue +++ b/src/layout/components/NavBar/index.vue @@ -2,20 +2,20 @@ @@ -23,7 +23,7 @@ diff --git a/src/main.ts b/src/main.ts index 062319e..27f5259 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,9 +1,12 @@ -import { createApp } from 'vue'; import 'animate.css'; -import App from './App.vue'; -import plugins from '@/plugins'; import '@unocss/reset/tailwind-compat.css'; import 'uno.css'; import 'virtual:unocss-devtools'; +import { createApp } from 'vue'; + +import plugins from '@/plugins'; + +import App from './App.vue'; + createApp(App).use(plugins).mount('#app'); diff --git a/src/plugins/index.ts b/src/plugins/index.ts index c11597a..6b23b4a 100644 --- a/src/plugins/index.ts +++ b/src/plugins/index.ts @@ -1,15 +1,16 @@ import type { App } from 'vue'; + import { setupDirective } from '@/directive'; import { setUpRouter } from '@/router'; import { setupStore } from '@/store'; export default { - install(app: App) { - // 设置路由 - setUpRouter(app); - // 设置状态管理 - setupStore(app); - // 设置指令 - setupDirective(app); - }, + install(app: App) { + // 设置路由 + setUpRouter(app); + // 设置状态管理 + setupStore(app); + // 设置指令 + setupDirective(app); + }, }; diff --git a/src/router/index.ts b/src/router/index.ts index ac3dcef..d0826b9 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -5,57 +5,57 @@ export const Layout = () => import('@/layout/index.vue'); // 静态路由 const routes: RouteRecordRaw[] = [ - { - path: '/redirect', - component: Layout, - meta: { hidden: true }, - children: [ - { - path: '/redirect/:path(.*)', - component: () => import('@/views/redirect/index.vue'), - }, - ], - }, - { - path: '/', - name: '/', - component: Layout, - // redirect: '/dashboard', - children: [ - // { - // path: 'dashboard', - // component: () => import('@/views/index.vue'), - // // 用于 keep-alive 功能,需要与 SFC 中自动推导或显式声明的组件名称一致 - // // 参考文档: https://cn.vuejs.org/guide/built-ins/keep-alive.html#include-exclude - // name: 'Dashboard', - // meta: { - // title: 'dashboard', - // icon: 'homepage', - // affix: true, - // keepAlive: true, - // }, - // }, - ], - }, - { - path: '/404', - component: () => import('@/views/error-page/404.vue'), - meta: { hidden: true }, - }, + { + path: '/redirect', + component: Layout, + meta: { hidden: true }, + children: [ + { + path: '/redirect/:path(.*)', + component: () => import('@/views/redirect/index.vue'), + }, + ], + }, + { + path: '/', + name: '/', + component: Layout, + // redirect: '/dashboard', + children: [ + // { + // path: 'dashboard', + // component: () => import('@/views/index.vue'), + // // 用于 keep-alive 功能,需要与 SFC 中自动推导或显式声明的组件名称一致 + // // 参考文档: https://cn.vuejs.org/guide/built-ins/keep-alive.html#include-exclude + // name: 'Dashboard', + // meta: { + // title: 'dashboard', + // icon: 'homepage', + // affix: true, + // keepAlive: true, + // }, + // }, + ], + }, + { + path: '/error', + component: () => import('@/views/error-page/404.vue'), + meta: { hidden: true }, + }, ]; const router = createRouter({ - history: createWebHashHistory(), - routes, - scrollBehavior: () => ({ x: 0, y: 0 }), + history: createWebHashHistory(), + routes, + scrollBehavior: () => ({ x: 0, y: 0 }), }); /** 全局注册 router */ export const setUpRouter = (app: App) => { - app.use(router); + app.use(router); }; /** 重置路由 */ export const resetRouter = () => { - router.replace({ path: '/' }).then(); + router.replace({ path: '/' }).then(); }; export default router; diff --git a/src/store/index.ts b/src/store/index.ts index 24ed9e4..899e282 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,9 +1,9 @@ -import type { App } from 'vue'; import { createPinia } from 'pinia'; +import type { App } from 'vue'; const store = createPinia(); // 全局注册 store export function setupStore(app: App) { - app.use(store); + app.use(store); } diff --git a/src/types/global.d.ts b/src/types/global.d.ts index a8afb09..b27c3ca 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -1,12 +1,13 @@ declare global { - /* 环境便配置 */ - declare interface ViteEnv { - VITE_APP_TITLE: string; - VITE_PORT: number; - VITE_PUBLIC_PATH: string; - VITE_APP_URL: string; - VITE_STRICT_PORT: boolean; - VITE_CDN: boolean; - VITE_COMPRESSION: string; - } + /* 环境便配置 */ + declare interface ViteEnv { + VITE_APP_TITLE: string; + VITE_PORT: number; + VITE_PUBLIC_PATH: string; + VITE_APP_URL: string; + VITE_STRICT_PORT: boolean; + VITE_POST_CSS_PX_TO_VIEWPORT8_PLUGIN: boolean; + VITE_CDN: boolean; + VITE_COMPRESSION: string; + } } diff --git a/src/utils/nprogress.ts b/src/utils/nprogress.ts index e9ba431..608e7da 100644 --- a/src/utils/nprogress.ts +++ b/src/utils/nprogress.ts @@ -1,18 +1,19 @@ -import NProgress from 'nprogress'; import 'nprogress/nprogress.css'; +import NProgress from 'nprogress'; + // 进度条 NProgress.configure({ - // 动画方式 - easing: 'ease', - // 递增进度条的速度 - speed: 500, - // 是否显示加载ico - showSpinner: false, - // 自动递增间隔 - trickleSpeed: 200, - // 初始化时的最小百分比 - minimum: 0.3, + // 动画方式 + easing: 'ease', + // 递增进度条的速度 + speed: 500, + // 是否显示加载ico + showSpinner: false, + // 自动递增间隔 + trickleSpeed: 200, + // 初始化时的最小百分比 + minimum: 0.3, }); export default NProgress; diff --git a/src/utils/request.ts b/src/utils/request.ts index 7944688..79ad1bf 100644 --- a/src/utils/request.ts +++ b/src/utils/request.ts @@ -1,70 +1,71 @@ import axios, { type AxiosResponse, type InternalAxiosRequestConfig } from 'axios'; -import { useUserStoreHook } from '@/store/modules/user'; -import { ResultEnum } from '@/enums/ResultEnum'; -import { TOKEN_KEY } from '@/enums/CacheEnum'; import qs from 'qs'; +import { TOKEN_KEY } from '@/enums/CacheEnum'; +import { ResultEnum } from '@/enums/ResultEnum'; +import { useUserStoreHook } from '@/store/modules/user'; + // 创建 axios 实例 const service = axios.create({ - baseURL: import.meta.env.VITE_APP_BASE_API, - timeout: 50000, - headers: { 'Content-Type': 'application/json;charset=utf-8' }, - paramsSerializer: params => { - return qs.stringify(params); - }, + baseURL: import.meta.env.VITE_APP_BASE_API, + timeout: 50000, + headers: { 'Content-Type': 'application/json;charset=utf-8' }, + paramsSerializer: (params) => { + return qs.stringify(params); + }, }); // 请求拦截器 service.interceptors.request.use( - (config: InternalAxiosRequestConfig) => { - const accessToken = localStorage.getItem(TOKEN_KEY); - if (accessToken) { - config.headers.Authorization = accessToken; - } - return config; - }, - (error: any) => { - return Promise.reject(error); - }, + (config: InternalAxiosRequestConfig) => { + const accessToken = localStorage.getItem(TOKEN_KEY); + if (accessToken) { + config.headers.Authorization = accessToken; + } + return config; + }, + (error: any) => { + return Promise.reject(error); + } ); // 响应拦截器 service.interceptors.response.use( - (response: AxiosResponse) => { - // 检查配置的响应类型是否为二进制类型('blob' 或 'arraybuffer'), 如果是,直接返回响应对象 - if (response.config.responseType === 'blob' || response.config.responseType === 'arraybuffer') { - return response; - } + (response: AxiosResponse) => { + // 检查配置的响应类型是否为二进制类型('blob' 或 'arraybuffer'), 如果是,直接返回响应对象 + if (response.config.responseType === 'blob' || response.config.responseType === 'arraybuffer') { + return response; + } - const { code, data, msg } = response.data; - if (code === ResultEnum.SUCCESS) { - return data; - } + const { code, data, msg } = response.data; + if (code === ResultEnum.SUCCESS) { + return data; + } - ElMessage.error(msg || '系统出错'); - return Promise.reject(new Error(msg || 'Error')); - }, - (error: any) => { - // 异常处理 - if (error.response.data) { - const { code, msg } = error.response.data; - if (code === ResultEnum.TOKEN_INVALID) { - ElNotification({ - title: '提示', - message: '您的会话已过期,请重新登录', - type: 'info', - }); - useUserStoreHook() - .resetToken() - .then(() => { - location.reload(); - }); - } else { - ElMessage.error(msg || '系统出错'); - } - } - return Promise.reject(error.message); - }, + ElMessage.error(msg || '系统出错'); + return Promise.reject(new Error(msg || 'Error')); + }, + (error: any) => { + // 异常处理 + if (error.response.data) { + const { code, msg } = error.response.data; + if (code === ResultEnum.TOKEN_INVALID) { + ElNotification({ + title: '提示', + message: '您的会话已过期,请重新登录', + type: 'info', + }); + useUserStoreHook() + .resetToken() + .then(() => { + location.reload(); + }); + } else { + ElMessage.error(msg || '系统出错'); + } + } + return Promise.reject(error.message); + } ); // 导出 axios 实例 diff --git a/src/views/error-page/404.vue b/src/views/error-page/404.vue index 8494b71..6a9395f 100644 --- a/src/views/error-page/404.vue +++ b/src/views/error-page/404.vue @@ -1,5 +1,5 @@ @@ -7,10 +7,10 @@ const router = useRouter(); diff --git a/stylelint.config.js b/stylelint.config.js index 2e16401..03d3ff5 100644 --- a/stylelint.config.js +++ b/stylelint.config.js @@ -1,51 +1,51 @@ module.exports = { - // 继承推荐规范配置 - extends: [ - 'stylelint-config-standard', - 'stylelint-config-recommended-scss', - 'stylelint-config-recommended-vue/scss', - 'stylelint-config-html/vue', - 'stylelint-config-recess-order', - ], - // 指定不同文件对应的解析器 - overrides: [ - { - files: ['**/*.{vue,html}'], - customSyntax: 'postcss-html', - }, - { - files: ['**/*.{css,scss}'], - customSyntax: 'postcss-scss', - }, - ], - // 自定义规则 - rules: { - 'import-notation': 'string', // 指定导入CSS文件的方式("string"|"url") - 'selector-class-pattern': null, // 选择器类名命名规则 - 'custom-property-pattern': null, // 自定义属性命名规则 - 'keyframes-name-pattern': null, // 动画帧节点样式命名规则 - 'no-descending-specificity': null, // 允许无降序特异性 - 'no-empty-source': null, // 允许空样式 - // 允许 global 、export 、deep伪类 - 'selector-pseudo-class-no-unknown': [ - true, - { - ignorePseudoClasses: ['global', 'export', 'deep'], - }, - ], - // 允许未知属性 - 'property-no-unknown': [ - true, - { - ignoreProperties: [], - }, - ], - // 允许未知规则 - 'at-rule-no-unknown': [ - true, - { - ignoreAtRules: ['apply', 'use', 'forward'], - }, - ], - }, + // 继承推荐规范配置 + extends: [ + 'stylelint-config-standard', + 'stylelint-config-recommended-scss', + 'stylelint-config-recommended-vue/scss', + 'stylelint-config-html/vue', + 'stylelint-config-recess-order', + ], + // 指定不同文件对应的解析器 + overrides: [ + { + files: ['**/*.{vue,html}'], + customSyntax: 'postcss-html', + }, + { + files: ['**/*.{css,scss}'], + customSyntax: 'postcss-scss', + }, + ], + // 自定义规则 + rules: { + 'import-notation': 'string', // 指定导入CSS文件的方式("string"|"url") + 'selector-class-pattern': null, // 选择器类名命名规则 + 'custom-property-pattern': null, // 自定义属性命名规则 + 'keyframes-name-pattern': null, // 动画帧节点样式命名规则 + 'no-descending-specificity': null, // 允许无降序特异性 + 'no-empty-source': null, // 允许空样式 + // 允许 global 、export 、deep伪类 + 'selector-pseudo-class-no-unknown': [ + true, + { + ignorePseudoClasses: ['global', 'export', 'deep'], + }, + ], + // 允许未知属性 + 'property-no-unknown': [ + true, + { + ignoreProperties: [], + }, + ], + // 允许未知规则 + 'at-rule-no-unknown': [ + true, + { + ignoreAtRules: ['apply', 'use', 'forward'], + }, + ], + }, }; diff --git a/uno.config.ts b/uno.config.ts index 2ba0311..3c89a86 100644 --- a/uno.config.ts +++ b/uno.config.ts @@ -7,18 +7,22 @@ import { presetWebFonts, transformerDirectives, transformerVariantGroup, -} from "unocss"; +} from 'unocss'; export default defineConfig({ shortcuts: { - "flex-center": "flex justify-center items-center", - "flex-x-between": "flex items-center justify-between", - "flex-x-around": "flex items-center justify-around", - "flex-y-center": "flex flex-col flex-wrap justify-center items-center", + 'flex-center': 'flex justify-center items-center', + 'flex-x-between': 'flex items-center justify-between', + 'flex-x-around': 'flex items-center justify-around', + 'flex-y-center': 'flex flex-col flex-wrap justify-center items-center', + 'flex-y-between': 'flex flex-col flex-wrap justify-between items-center', }, theme: { colors: { - // ... + primary: '#027AFF', + 'primary-secondary': '#00FFFF', + warning: '#FFBE44', + 'warning-secondary': '#FEDB65', }, }, presets: [ diff --git a/vite.config.ts b/vite.config.ts index 893cdab..4479b11 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,16 +1,17 @@ -import { defineConfig } from "vite"; -import { plugins } from "./build/plugins"; -import { resolve } from "./build/resolve"; -import { buildEnv } from "./build/buildEnv"; -import { define } from "./build/define"; -import { root, wrapperEnv } from "./build/utils"; -import { server } from "./build/server"; -import { exclude, include } from "./build/optimize"; -import postCssPxToViewport8plugin from "postcss-px-to-viewport-8-plugin"; +import { defineConfig } from 'vite'; + +import { buildEnv } from './build/buildEnv'; +import { css } from './build/css'; +import { define } from './build/define'; +import { exclude, include } from './build/optimize'; +import { plugins } from './build/plugins'; +import { resolve } from './build/resolve'; +import { server } from './build/server'; +import { root, wrapperEnv } from './build/utils'; // https://vite.dev/config/ export default defineConfig(({ command, mode, isSsrBuild, isPreview }) => { - const env = wrapperEnv(mode, "VITE"); + const env = wrapperEnv(mode, 'VITE'); return { root, @@ -19,34 +20,12 @@ export default defineConfig(({ command, mode, isSsrBuild, isPreview }) => { plugins: plugins(mode), resolve: resolve(), esbuild: { - jsxFactory: "h", - jsxFragment: "Fragment", + jsxFactory: 'h', + jsxFragment: 'Fragment', jsxInject: "import { h } from 'vue';", }, - css: { - postcss: { - plugins: [ - postCssPxToViewport8plugin({ - unitToConvert: "px", - viewportWidth: 1920, // 设计稿的宽度 - unitPrecision: 5, // 单位转换后保留的精度 - propList: ["*"], // 能转化为vw的属性列表 - viewportUnit: "vw", // 希望使用的视口单位 - fontViewportUnit: "vw", // 字体使用的视口单位 - selectorBlackList: [], // 需要忽略的CSS选择器,不会转为视口单位,使用原有的px等单位。 - minPixelValue: 1, // 设置最小的转换数值,如果为1的话,只有大于1的值会被转换 - mediaQuery: true, // 媒体查询里的单位是否需要转换单位 - replace: true, // 是否直接更换属性值,而不添加备用属性 - exclude: [/node_modules/], // 忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件 - include: [], // 如果设置了include,那将只有匹配到的文件才会被转换 - landscape: false, // 是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape) - landscapeUnit: "vw", // 横屏时使用的单位 - landscapeWidth: 1024, // 横屏时使用的视口宽度 - }), - ], - }, - }, - logLevel: "info", + logLevel: 'info', + css: css(mode), // 设为 false 可以避免 Vite 清屏而错过在终端中打印某些关键信息 clearScreen: false, build: buildEnv(),