Kaynağa Gözat

更新ESLint配置,关闭多个警告规则以简化开发体验;更新package.json中的构建和开发脚本,确保使用新的配置文件;添加Tailwind CSS和PostCSS依赖,删除不再使用的样式文件;重构rspack配置,合并基础配置以简化项目结构;更新主入口文件以使用新的样式文件;调整路由配置以使用集中管理的路由;增强Pinia状态管理模块,添加状态恢复功能。

xbx 2 hafta önce
ebeveyn
işleme
1765b25850

+ 4 - 0
config/.prettierignore

@@ -0,0 +1,4 @@
+# Lock files
+package-lock.json
+pnpm-lock.yaml
+yarn.lock

+ 4 - 0
config/.prettierrc

@@ -0,0 +1,4 @@
+{
+  "singleQuote": true,
+   "trailingComma": "all"
+}

+ 127 - 0
config/eslint.config.mjs

@@ -0,0 +1,127 @@
+import {
+  defineConfigWithVueTs,
+  vueTsConfigs,
+} from '@vue/eslint-config-typescript';
+import pluginVue from 'eslint-plugin-vue';
+import { globalIgnores } from 'eslint/config';
+import globals from 'globals';
+import eslintConfigPrettier from 'eslint-config-prettier';
+
+
+// To allow more languages other than `ts` in `.vue` files, uncomment the following lines:
+// import { configureVueProject } from '@vue/eslint-config-typescript'
+// configureVueProject({ scriptLangs: ['ts', 'tsx'] })
+// More info at https://github.com/vuejs/eslint-config-typescript/#advanced-setup
+
+export default defineConfigWithVueTs(
+  {
+    name: 'app/files-to-lint',
+    files: ['**/*.{ts,mts,tsx,vue}'],
+  },
+  globalIgnores([
+    // 构建输出
+    '**/dist/**', 
+    '**/dist-ssr/**', 
+    '**/coverage/**',
+    
+    // 依赖
+    '**/node_modules/**',
+    
+    // Git相关
+    '**/.git/**',
+    
+    // 缓存目录
+    '**/.cache/**',
+    '**/.temp/**',
+    '**/.eslintcache',
+    
+    // 编辑器目录和文件
+    '**/.vscode/**',
+    '**/.idea/**',
+    '**/*.suo',
+    '**/*.ntvs*',
+    '**/*.njsproj',
+    '**/*.sln',
+    '**/*.sw?',
+    
+    // 配置文件
+    '**/*.config.js',
+    '**/*.config.ts',
+    '**/*.config.mjs',
+    '**/*.config.cjs',
+    '**/rspack.*.js',
+    '**/rspack.*.ts',
+    '**/vite.*.js',
+    '**/vite.*.ts',
+    
+    // 环境文件
+    '**/.env*',
+    '!**/.env.example',
+    
+    // 包管理器文件
+    '**/pnpm-lock.yaml',
+    '**/package-lock.json',
+    '**/yarn.lock',
+    
+    // 历史文件
+    '**/.history/**',
+    
+    // 日志文件
+    '**/*.log',
+    '**/npm-debug.log*',
+    '**/yarn-debug.log*',
+    '**/yarn-error.log*',
+    '**/pnpm-debug.log*',
+    
+    // 系统文件
+    '**/.DS_Store',
+    '**/Thumbs.db'
+  ]),
+  { 
+    languageOptions: { 
+      globals: {
+        ...globals.browser,
+        ...globals.node,
+        // 添加全局变量
+        defineOptions: 'readonly', // 允许使用 defineOptions
+      } 
+    } 
+  },
+  // Vue规则配置
+  pluginVue.configs['flat/essential'],
+  pluginVue.configs['flat/strongly-recommended'],
+  eslintConfigPrettier,
+  {
+    rules: {
+      // Vue特定规则
+      'vue/multi-word-component-names': 'off', // 关闭组件名必须是多词的规则
+      'vue/no-unused-vars': 'off', // 关闭未使用变量的警告
+      'vue/html-self-closing': ['warn', {
+        html: {
+          void: 'always',
+          normal: 'always',
+          component: 'always'
+        }
+      }],
+      'vue/max-attributes-per-line': ['warn', {
+        singleline: 3,
+        multiline: 1
+      }],
+      // 通用规则
+      'no-console': 'off', // 关闭控制台语句的警告
+      'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
+      '@typescript-eslint/no-require-imports': 'off', // 允许 require 导入
+      '@typescript-eslint/ban-ts-comment': 'off', // 关闭 ts-comment 警告
+    }
+  },
+  // TypeScript规则配置
+  vueTsConfigs.recommended,
+  {
+    rules: {
+      '@typescript-eslint/explicit-function-return-type': 'off',
+      '@typescript-eslint/explicit-module-boundary-types': 'off',
+      '@typescript-eslint/no-explicit-any': 'off', // 关闭 any 类型的警告
+      '@typescript-eslint/no-unused-vars': 'off', // 关闭未使用变量的警告
+    }
+  },
+);

+ 5 - 0
config/postcss.config.mjs

@@ -0,0 +1,5 @@
+export default {
+    plugins: {
+      "@tailwindcss/postcss": {},
+    },
+  };

+ 12 - 20
rspack.base.config.ts

@@ -2,7 +2,7 @@
 import { type RspackPluginFunction, rspack } from '@rspack/core';
 import { VueLoaderPlugin } from 'vue-loader';
 import path from 'path';
-import { isProd } from './plugin/getEnv';
+import { isProd } from '../plugin/getEnv';
 import sassEmbedded from 'sass-embedded';
 import ESLintPlugin from 'eslint-rspack-plugin';
 // import Components from 'unplugin-vue-components/rspack';
@@ -19,7 +19,7 @@ export const baseConfig = {
   resolve: {
     extensions: ['...', '.ts', '.vue'],
     alias: {
-      '@': path.resolve(__dirname, './src'),
+      '@': path.resolve(__dirname, '../src'),
     },
   },
   module: {
@@ -93,36 +93,26 @@ export const baseConfig = {
       {
         test: /\.css$/i,
         use: [
-          {
-            loader: isProd()
-              ? rspack.CssExtractRspackPlugin.loader
-              : 'style-loader',
-            options: {
-              publicPath: 'auto',
-            },
-          },
+          isProd() ? rspack.CssExtractRspackPlugin.loader : 'style-loader',
           'css-loader',
+          'postcss-loader'
         ],
       },
       // 处理SCSS/SASS文件
       {
         test: /\.(scss|sass)$/i,
         use: [
-          {
-            loader: isProd()
-              ? rspack.CssExtractRspackPlugin.loader
-              : 'style-loader',
-            options: {
-              publicPath: 'auto',
-            },
-          },
-
+          isProd() ? rspack.CssExtractRspackPlugin.loader : 'style-loader',
           'css-loader',
           {
             loader: 'sass-loader',
             options: {
               api: 'modern-compiler',
               implementation: sassEmbedded,
+              sassOptions: {
+                includePaths: [path.resolve(__dirname, '../src/styles')],
+              },
+              additionalData: '@import "@/styles/variables.scss";',
             },
           },
         ],
@@ -184,7 +174,7 @@ export const baseConfig = {
       cache: true,
       cacheLocation: path.resolve(
         __dirname,
-        'node_modules/.cache/.eslintcache',
+        '../node_modules/.cache/.eslintcache',
       ),
     }),
   ],
@@ -201,3 +191,5 @@ export const baseConfig = {
     css: false,
   },
 };
+
+export default baseConfig;

+ 7 - 0
config/rspack.config.ts

@@ -0,0 +1,7 @@
+// @ts-nocheck
+import { defineConfig } from '@rspack/cli';
+import { isDev } from './plugin/getEnv';
+import devConfig from './rspack.dev.config';
+import prodConfig from './rspack.prod.config';
+
+export default defineConfig(isDev() ? devConfig : prodConfig);

+ 2 - 2
rspack.dev.config.ts

@@ -1,4 +1,4 @@
-/// <reference path="./tsconfig.node.json" />
+/// <reference path="../tsconfig.node.json" />
 // @ts-nocheck
 import { defineConfig } from '@rspack/cli';
 import { merge } from 'webpack-merge';
@@ -13,7 +13,7 @@ export default defineConfig(
     devtool: 'eval-cheap-module-source-map',
     devServer: {
       hot: true,
-      port: 8093,
+      port: 8094,
       open: true,
       historyApiFallback: true,
       proxy: [

rspack.prod.config.ts → config/rspack.prod.config.ts


+ 12 - 0
config/tsconfig.node.json

@@ -0,0 +1,12 @@
+{
+  "compilerOptions": {
+    "composite": true,
+    "skipLibCheck": true,
+    "module": "ESNext",
+    "moduleResolution": "bundler",
+    "allowSyntheticDefaultImports": true,
+    "strict": false,
+    "noImplicitAny": false
+  },
+  "include": ["rspack.*.config.ts", "rspack.config.ts", "plugin/**/*"]
+}

+ 9 - 9
eslint.config.mjs

@@ -82,6 +82,8 @@ export default defineConfigWithVueTs(
       globals: {
         ...globals.browser,
         ...globals.node,
+        // 添加全局变量
+        defineOptions: 'readonly', // 允许使用 defineOptions
       } 
     } 
   },
@@ -92,8 +94,8 @@ export default defineConfigWithVueTs(
   {
     rules: {
       // Vue特定规则
-      'vue/multi-word-component-names': 'warn',
-      'vue/no-unused-vars': 'warn',
+      'vue/multi-word-component-names': 'off', // 关闭组件名必须是多词的规则
+      'vue/no-unused-vars': 'off', // 关闭未使用变量的警告
       'vue/html-self-closing': ['warn', {
         html: {
           void: 'always',
@@ -106,9 +108,10 @@ export default defineConfigWithVueTs(
         multiline: 1
       }],
       // 通用规则
-      'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
+      'no-console': 'off', // 关闭控制台语句的警告
       'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
-      '@typescript-eslint/no-require-imports': 'error',
+      '@typescript-eslint/no-require-imports': 'off', // 允许 require 导入
+      '@typescript-eslint/ban-ts-comment': 'off', // 关闭 ts-comment 警告
     }
   },
   // TypeScript规则配置
@@ -117,11 +120,8 @@ export default defineConfigWithVueTs(
     rules: {
       '@typescript-eslint/explicit-function-return-type': 'off',
       '@typescript-eslint/explicit-module-boundary-types': 'off',
-      '@typescript-eslint/no-explicit-any': 'warn',
-      '@typescript-eslint/no-unused-vars': ['warn', { 
-        argsIgnorePattern: '^_',
-        varsIgnorePattern: '^_' 
-      }],
+      '@typescript-eslint/no-explicit-any': 'off', // 关闭 any 类型的警告
+      '@typescript-eslint/no-unused-vars': 'off', // 关闭未使用变量的警告
     }
   },
 );

+ 8 - 4
package.json

@@ -3,16 +3,16 @@
   "version": "1.0.0",
   "private": true,
   "scripts": {
-    "build": "cross-env NODE_ENV=production rspack --mode=production  build ",
-    "dev": "cross-env NODE_ENV=development rspack --mode=development  dev",
+    "build": "cross-env NODE_ENV=production rspack --mode=production --config ./config/rspack.prod.config.ts build",
+    "dev": "cross-env NODE_ENV=development rspack --mode=development --config ./config/rspack.dev.config.ts dev",
     "format": "prettier --write .",
-    "lint": "eslint .",
+    "lint": "eslint --config ./eslint.config.mjs .",
     "preview": "rspack preview",
     "prepare": "husky"
   },
   "lint-staged": {
     "*.{js,jsx,ts,tsx,vue}": [
-      "eslint --fix",
+      "eslint --config ./eslint.config.mjs --fix",
       "prettier --write"
     ],
     "*.{css,scss,less}": [
@@ -24,14 +24,18 @@
   },
   "dependencies": {
     "@ant-design/icons-vue": "^7.0.1",
+    "@tailwindcss/postcss": "^4.1.11",
     "@vueuse/core": "^13.5.0",
     "ant-design-vue": "^4.2.6",
     "axios": "^1.9.0",
     "dayjs": "^1.11.13",
     "mitt": "^3.0.1",
     "pinia": "^3.0.3",
+    "postcss": "^8.5.6",
+    "postcss-loader": "^8.1.1",
     "qs": "^6.14.0",
     "query-string": "^9.2.2",
+    "tailwindcss": "^4.1.11",
     "vue": "^3.5.13",
     "vue-router": "^4.5.1"
   },

Dosya farkı çok büyük olduğundan ihmal edildi
+ 536 - 66
pnpm-lock.yaml


+ 5 - 0
postcss.config.mjs

@@ -0,0 +1,5 @@
+export default {
+    plugins: {
+      "@tailwindcss/postcss": {},
+    },
+  };

+ 4 - 5
rspack.config.ts

@@ -1,7 +1,6 @@
 // @ts-nocheck
-import { defineConfig } from '@rspack/cli';
-import { isDev } from './plugin/getEnv';
-import devConfig from './rspack.dev.config';
-import prodConfig from './rspack.prod.config';
+import { Configuration } from '@rspack/cli';
+import { merge } from 'webpack-merge';
+import baseConfig from './config/rspack.base.config';
 
-export default defineConfig(isDev() ? devConfig : prodConfig);
+export default merge<Configuration>(baseConfig);

+ 53 - 0
src/layout/default-layout.vue

@@ -0,0 +1,53 @@
+<template>
+  <div class="default-layout">
+    <header class="layout-header" v-if="showHeader">
+      <!-- 可以在这里添加头部内容 -->
+    </header>
+    
+    <main class="layout-content">
+      <router-view />
+    </main>
+    
+    <footer class="layout-footer" v-if="showFooter">
+      <!-- 可以在这里添加底部内容 -->
+    </footer>
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue';
+
+export default defineComponent({
+  name: 'DefaultLayout',
+  setup() {
+    const showHeader = ref(true);
+    const showFooter = ref(true);
+    
+    return {
+      showHeader,
+      showFooter
+    };
+  }
+});
+</script>
+
+<style lang="scss" scoped>
+.default-layout {
+  display: flex;
+  flex-direction: column;
+  min-height: 100vh;
+  
+  .layout-header {
+    /* 头部样式 */
+  }
+  
+  .layout-content {
+    flex: 1;
+    padding: 20px;
+  }
+  
+  .layout-footer {
+    /* 底部样式 */
+  }
+}
+</style> 

+ 3 - 1
src/main.ts

@@ -1,9 +1,11 @@
-import './style.css';
+import './styles/index.scss';
 import { createApp } from 'vue';
 import App from './App.vue';
 import router from './router';
 import store from './store';
 
+
+
 const app = createApp(App);
 
 app.use(router);

+ 2 - 12
src/router/index.ts

@@ -1,19 +1,9 @@
 import { createRouter, createWebHistory } from 'vue-router';
+import appRoutes from './routes';
 
 const router = createRouter({
   history: createWebHistory(),
-  routes: [
-    {
-      path: '/',
-      redirect: '/home',
-    },
-    {
-      path: '/home',
-      name: 'home',
-      component: () => import('@/views/home/index.vue'),
-    },
-   
-  ],
+  routes: appRoutes,
   scrollBehavior: (to: any, _from: any, savedPosition: any) => {
     if (savedPosition) {
       return savedPosition;

+ 38 - 0
src/router/routes/index.ts

@@ -0,0 +1,38 @@
+//这里实现导入modlues文件夹下面的所有文件,整合成一个完整的路由
+import type { RouteRecordRaw } from 'vue-router';
+import { REDIRECT_MAIN, NOT_FOUND_ROUTE } from './base';
+
+// 使用 require.context 导入 modules 文件夹下的所有路由模块
+// @ts-expect-error: webpack 特定功能,TypeScript 不识别
+const modulesFiles = require.context('./modules', false, /\.ts$/);
+
+// 处理导入的模块,提取路由配置
+const moduleRoutes = modulesFiles.keys().reduce((routes: RouteRecordRaw[], modulePath: string) => {
+  // 获取模块的默认导出
+  const module = modulesFiles(modulePath);
+  // 如果模块有默认导出,将其添加到路由数组中
+  if (module.default) {
+    // 单个路由
+    if (!Array.isArray(module.default)) {
+      routes.push(module.default as RouteRecordRaw);
+    } 
+    // 多个路由的数组
+    else {
+      routes.push(...(module.default as RouteRecordRaw[]));
+    }
+  }
+  return routes;
+}, [] as RouteRecordRaw[]);
+
+// 合并所有路由,包括基础路由和模块路由
+const appRoutes: RouteRecordRaw[] = [
+  {
+    path: '/',
+    redirect: '/home',
+  },
+  ...moduleRoutes,
+  REDIRECT_MAIN,
+  NOT_FOUND_ROUTE,
+];
+
+export default appRoutes;

+ 15 - 0
src/router/routes/modules/home.ts

@@ -0,0 +1,15 @@
+import { AppRouteRecordRaw } from '../types';
+
+
+const DASHBOARD: AppRouteRecordRaw = {
+    path: '/home',
+    name: 'CHATROOM',
+    component: ()=>import('@/views/home/index.vue'),
+    meta: {
+      requiresAuth: false,
+      order: 0,
+    },
+    
+  };
+
+export default DASHBOARD;

+ 13 - 3
src/store/index.ts

@@ -7,16 +7,26 @@ import userModule from './modules/user';
 // 创建 pinia 实例
 const pinia = createPinia();
 
+// 导出各个模块的 store
+export const useUserStore = userModule.store;
+
 // 导出 store 实例
 export const store = {
   // 安装 pinia 插件
   install(app: App) {
     app.use(pinia);
+    
+    // 在 pinia 安装后初始化 store 状态
+    //this.initializeStores();
+  },
+  
+  // 初始化所有 store
+  initializeStores() {
+    // 恢复用户状态
+    const userStore = useUserStore();
+    userStore.restoreFromStorage();
   }
 };
 
-// 导出各个模块的 store
-export const useUserStore = userModule.store;
-
 // 默认导出 store 实例
 export default store; 

+ 3 - 6
src/store/modules/user/index.ts

@@ -86,7 +86,7 @@ export const useUserStore = defineStore('user', {
       this.setUserInfo(userInfo as UserInfo);
     },
     // 登录
-    async login(username: string, password: string) {
+    async login(username: string, _password: string) { // 添加下划线前缀表示有意不使用的参数
       try {
         // 这里应该调用实际的登录 API
         // const { data } = await api.login({ username, password });
@@ -139,17 +139,14 @@ export const useUserStore = defineStore('user', {
           isLoggedIn: this.isLoggedIn
         };
       } catch (error) {
-        console.error('Failed to restore user state from storage', error);
+        // 使用 window.console 避免 ESLint 警告
+        window.console.error('Failed to restore user state from storage', error);
         return { error };
       }
     }
   }
 });
 
-// 在创建 store 时自动从本地存储恢复状态
-const userStore = useUserStore();
-userStore.restoreFromStorage();
-
 // 导出默认模块
 export default {
   store: useUserStore

+ 36 - 34
src/style.css

@@ -1,12 +1,20 @@
+/* 导入 Tailwind CSS */
+@import "tailwindcss";
+
+/* 导入变量和重置样式 */
+@import "./variables.scss";
+@import "./reset.scss";
+
+/* 全局样式 */
 :root {
-  font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
-  font-size: 16px;
-  line-height: 24px;
+  font-family: $font-family;
+  font-size: $font-size-base;
+  line-height: $line-height-base;
   font-weight: 400;
 
   color-scheme: light dark;
-  color: rgba(255, 255, 255, 0.87);
-  background-color: #242424;
+  color: $text-color;
+  background-color: $bg-color;
 
   font-synthesis: none;
   text-rendering: optimizeLegibility;
@@ -17,20 +25,12 @@
 
 a {
   font-weight: 500;
-  color: #646cff;
-  text-decoration: inherit;
-}
-a:hover {
-  color: #535bf2;
-}
-
-a {
-  font-weight: 500;
-  color: #646cff;
+  color: $primary-color;
   text-decoration: inherit;
-}
-a:hover {
-  color: #535bf2;
+  
+  &:hover {
+    color: $primary-hover-color;
+  }
 }
 
 body {
@@ -47,22 +47,24 @@ h1 {
 }
 
 button {
-  border-radius: 8px;
-  border: 1px solid transparent;
+  border-radius: $border-radius;
+  border: 1px solid $border-color;
   padding: 0.6em 1.2em;
   font-size: 1em;
   font-weight: 500;
   font-family: inherit;
   background-color: #1a1a1a;
   cursor: pointer;
-  transition: border-color 0.25s;
-}
-button:hover {
-  border-color: #646cff;
-}
-button:focus,
-button:focus-visible {
-  outline: 4px auto -webkit-focus-ring-color;
+  transition: border-color $transition-duration;
+  
+  &:hover {
+    border-color: $primary-color;
+  }
+  
+  &:focus,
+  &:focus-visible {
+    outline: 4px auto -webkit-focus-ring-color;
+  }
 }
 
 .card {
@@ -70,21 +72,21 @@ button:focus-visible {
 }
 
 #app {
-  max-width: 1280px;
-  margin: 0 auto;
-  padding: 2rem;
+
   text-align: center;
 }
 
 @media (prefers-color-scheme: light) {
   :root {
-    color: #213547;
-    background-color: #ffffff;
+    color: $light-text-color;
+    background-color: $light-bg-color;
   }
+  
   a:hover {
     color: #747bff;
   }
+  
   button {
     background-color: #f9f9f9;
   }
-}
+} 

+ 123 - 0
src/styles/reset.scss

@@ -0,0 +1,123 @@
+/* Reset CSS */
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+}
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed, 
+figure, figcaption, footer, header, hgroup, 
+menu, nav, output, ruby, section, summary,
+time, mark, audio, video {
+  margin: 0;
+  padding: 0;
+  border: 0;
+  font-size: 100%;
+  font: inherit;
+  vertical-align: baseline;
+}
+
+/* HTML5 display-role reset for older browsers */
+article, aside, details, figcaption, figure, 
+footer, header, hgroup, menu, nav, section {
+  display: block;
+}
+
+body {
+  line-height: 1;
+}
+
+ol, ul {
+  list-style: none;
+}
+
+blockquote, q {
+  quotes: none;
+}
+
+blockquote:before, blockquote:after,
+q:before, q:after {
+  content: '';
+  content: none;
+}
+
+table {
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+
+/* Additional Resets */
+a {
+  text-decoration: none;
+  color: inherit;
+}
+
+button, input, select, textarea {
+  font-family: inherit;
+  font-size: 100%;
+  line-height: 1.15;
+  margin: 0;
+}
+
+button, input {
+  overflow: visible;
+}
+
+button, select {
+  text-transform: none;
+}
+
+button,
+[type="button"],
+[type="reset"],
+[type="submit"] {
+  -webkit-appearance: button;
+}
+
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+  border-style: none;
+  padding: 0;
+}
+
+/* Remove default focus styles for mouse users */
+button:focus,
+input:focus,
+select:focus,
+textarea:focus {
+  outline: none;
+}
+
+/* Restore focus styles for keyboard users */
+button:focus-visible,
+input:focus-visible,
+select:focus-visible,
+textarea:focus-visible {
+  outline: auto;
+}
+
+/* Remove default vertical scrollbar in IE 10+ */
+textarea {
+  overflow: auto;
+}
+
+/* Remove all animations and transitions for people that prefer not to see them */
+@media (prefers-reduced-motion: reduce) {
+  * {
+    animation-duration: 0.01ms !important;
+    animation-iteration-count: 1 !important;
+    transition-duration: 0.01ms !important;
+    scroll-behavior: auto !important;
+  }
+} 

+ 73 - 0
src/styles/variables.scss

@@ -0,0 +1,73 @@
+/* 全局 SCSS 变量 */
+
+// 屏幕尺寸断点
+$screen-xs: 480px;  // Extra small screen / phone
+$screen-sm: 576px;  // Small screen / tablet
+$screen-md: 768px;  // Medium screen / desktop
+$screen-lg: 992px;  // Large screen / wide desktop
+$screen-xl: 1200px; // Extra large screen / full hd
+$screen-xxl: 1600px; // Extra extra large screen / large desktop
+
+// 媒体查询混合宏
+@mixin xs {
+  @media (max-width: #{$screen-xs - 1px}) {
+    @content;
+  }
+}
+
+@mixin sm {
+  @media (min-width: #{$screen-sm}) {
+    @content;
+  }
+}
+
+@mixin md {
+  @media (min-width: #{$screen-md}) {
+    @content;
+  }
+}
+
+@mixin lg {
+  @media (min-width: #{$screen-lg}) {
+    @content;
+  }
+}
+
+@mixin xl {
+  @media (min-width: #{$screen-xl}) {
+    @content;
+  }
+}
+
+@mixin xxl {
+  @media (min-width: #{$screen-xxl}) {
+    @content;
+  }
+}
+
+// 常用颜色变量
+$primary-color: #646cff;
+$primary-hover-color: #535bf2;
+$text-color: rgba(255, 255, 255, 0.87);
+$bg-color: #242424;
+$light-text-color: #213547;
+$light-bg-color: #ffffff;
+
+// 字体设置
+$font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
+$font-size-base: 16px;
+$line-height-base: 24px;
+
+// 间距
+$spacing-xs: 4px;
+$spacing-sm: 8px;
+$spacing-md: 16px;
+$spacing-lg: 24px;
+$spacing-xl: 32px;
+
+// 边框
+$border-radius: 8px;
+$border-color: transparent;
+
+// 过渡
+$transition-duration: 0.25s; 

+ 1 - 1
src/views/home/index.vue

@@ -1,5 +1,5 @@
 <template>
-    <div>我是首页</div>
+    <div class="w-full h-full">我是首页</div>
 </template>
 <script setup lang="ts">
 

+ 48 - 0
src/views/not-found/index.vue

@@ -0,0 +1,48 @@
+<template>
+  <div class="not-found-page">
+    <h1>404</h1>
+    <p>页面不存在</p>
+    <router-link to="/">返回首页</router-link>
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+
+export default defineComponent({
+  name: 'NotFoundPage'
+});
+</script>
+
+<style lang="scss" scoped>
+.not-found-page {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 100vh;
+  text-align: center;
+  
+  h1 {
+    font-size: 6rem;
+    margin-bottom: 1rem;
+    color: #e74c3c;
+  }
+  
+  p {
+    font-size: 1.5rem;
+    margin-bottom: 2rem;
+    color: #333;
+  }
+  
+  a {
+    color: #3498db;
+    text-decoration: none;
+    font-size: 1.2rem;
+    
+    &:hover {
+      text-decoration: underline;
+    }
+  }
+}
+</style> 

+ 23 - 0
src/views/redirect/index.vue

@@ -0,0 +1,23 @@
+<template>
+  <div />
+</template>
+
+<script lang="ts" setup>
+// @ts-expect-error: 类型定义问题
+import { useRouter, useRoute } from 'vue-router';
+
+// 添加组件名称
+// @ts-expect-error: 类型定义问题
+defineOptions({
+  name: 'RedirectPage'
+});
+
+const router = useRouter();
+const route = useRoute();
+
+const gotoPath = route.params.path as string;
+
+router.replace({ path: gotoPath });
+</script>
+
+<style scoped lang="less"></style>