【项目】基于Vue3.2+ElementUI Plus+Vite 通用后台管理系统

news2024/11/16 1:34:06

构建项目

环境配置

  1. 全局安装vue脚手架

    npm install -g @vue/cli-init
    
  2. 打开脚手架图形化界面

    vue ui
    

创建项目

  1. 在图形化界面创建项目image-20240715235821607
  2. 根据要求填写项目相关信息image-20240715235939913
  3. 选择手动配置image-20240716000403670
  4. 勾选配置项目外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  5. 选择配置项目image-20240716000640751
  6. 然后我们就搭建完成啦🥳,构建可能需要一点时间,大家稍等久一会。

安装依赖

  1. 在右侧边栏找到依赖image-20240716003333732

  2. 安装axios依赖image-20240716003433503

  3. 运行项目

    npm run serve
    

配置git commit规范

什么是commit规范?

Git commit规范是指为了使版本控制更加清晰、易于追踪和维护,而在提交代码时遵循的一系列约定。一个良好的Git commit规范能够帮助团队成员理解每一次提交的目的和范围,同时便于后续的代码审查、问题追踪以及生成变更日志。

以下是一些常见的Git commit规范要点:

  • feat:添加新特性
  • fix:修复bug
  • docs:仅仅修改了文档
  • style:仅仅修改了空格、格式缩进、逗号等等,不改变代码逻辑
  • refactor:代码重构,没有加新功能或者修复bug
  • perf:优化相关,比如提升性能、体验
  • test:增加测试用例
  • chore:改变构建流程、或者增加依赖库、工具等
  • revert:回滚到上一个版本

下面是提交规范的配置步骤:

  1. 在vscode终端中,安装commitizen和cz-customizable

    npm install -g commitizen@4.2.4
    npm i cz-customizable@6.3.0--save-dev
    //如果第二个安装不成功可以使用下面这个
    npm i cz-customizable@6.3.0 --save-dev --force
    
  2. 在package.json中进行新增下面语句:

    "config": {
      "commitizen": {
        "path": "node_modules/cz-customizable"
      }
    }
    
  3. 在根目录下新建.cz-config.js文件并写入配置 之后就可以用 git cz 来代替 git commit

  4. 最后我们可以尝试git添加上传,再使用git cz检测是否安装成功

    //上传git
    git add .
    //git commit提交
    git cz
    
  5. 出现以下👇情况就是安装成功啦🥳image-20240716112207070

内容补充:

Commitizen的介绍:是一个用于撰写Git提交信息的工具。它可以帮助开发人员遵循一个规范,以便更容易地阅读和维护Git仓库历史记录。Commitizen采用了一个交互式的命令行界面,引导你逐步填写必要的数据,从而生成符合规范的Git提交信息。

cz-customizable的介绍:是一个Commitizen的插件,它允许你使用自定义的Git提交规范。通过为项目添加一个配置文件,你可以指定你自己的提交格式,并在使用Commitizen时使用该格式。你可以轻松地定义自己的提交类型、作用域和描述等信息。

配置强制commit规范

为什么需要强制约束commit规范?因为正常工作中多人协作的时候每个人的习惯不一样,所以我们需要强制性的进行规范化处理。

我们通过安装commitlint来实现强制性规范commit。

npm install --save-dev @commitlint/config-conventional@12.1.4 @commitlint/cli@12.1.4

然后安装husky进行强制git代码提交规范。

npm install husky@7.0.1 --save-dev

最后对husky进行初始化。

npx husky install

如果在文件夹中出现了多出来了这一个文件就说明成功了🥳

image-20240716155023849

问题补充:

如果安装commitlint未成功,可能是因为这是因为@vue/eslint-config-standard@6.1.0 依赖于 eslint-plugin-vue@^7.0.0,但是你的项目中已经安装了 eslint-plugin-vue@8.7.1,版本过高导致的。这里我也写了一片解决办法

别急!我们还有后续步骤:

  1. 添加commitlint.config.js文件到项目当中

  2. package.json文件中添加以下👇指令:

    "prepare": "husky install"
    
  3. 执行指令

    npm run prepare
    
  4. .husky中添加commit配置文件,在终端输入以下指令

    npx husky add .husky/commit-msg
    

    如果在这个文件夹中新增了这个commit文件就说明配置成功了

  5. 最后修改commit-msg文件,是为了hosky和commitlik实现关联

    npx --no-install commitlint --edit
    

强制规范我们就配置完啦,接下来测试一下

首先将文件添加到仓库当中:
	git add .
然后来一个不符合规矩的提交:
	git commit -m '这是不符合规矩的'

image-20240716161259821

再来一个符合规矩的操作:
git add .
git commit -m 'feat: 符合规矩的'

这样强制规范我们就配置好啦🥳!!!

代码格式化

同样的,代码格式我们也要实现强制格式化,这样防止我们写着写着就忘记了代码规范,以免错乱。

  1. 执行指令添加代码强制格式化文件

    npx husky add .husky/pre-commit
    

    添加成功就会多出一个代码强制格式化文件出来:image-20240716161902365

  2. 在新增加的文件中写入下面这段话:

    npx lint-staged
    
  3. package.json文件中添加:

    "lint-staged": {
       "src/**/*.{js,vue}": [      //src目录下所有的js和vue文件
         "eslint --fix",           // 自动修复
         "git add"                 // 自动提交时修复
       ]
     }
     注意:上面的注释需要删掉!!!
    

安装UI组件库

这里我们使用到的是Element Plus UI组件库,这个是他的安装 | Element Plus (element-plus.org)地址。我这里也简要描述一下他的安装步骤:

  1. 在项目终端中执行安装组件库命令:

    npm install element-plus --save
    
  2. 按需导入组件

    npm install -D unplugin-vue-components unplugin-auto-import
    
  3. 创建vue.config.js文件,将以下👇代码导入

    //两个版本,如果第一个报错的话就用第二个,第二个是我自己找来配置的,建议先使用up提供的,这样才能保证与视频项目配置一致。
    
    const AutoImport = require('unplugin-auto-import/webpack')
    const Components = require('unplugin-vue-components/webpack')
    const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
    
    module.exports = {
      configureWebpack: config => {
        config.plugins.push(AutoImport({
          resolvers: [ElementPlusResolver()],
        }))
        config.plugins.push(Components({
          resolvers: [ElementPlusResolver()],
        }))
      },
    }
    
    //第二个版本,我自己配置的(上面一个不可用,在使用我这个)
    const { defineConfig } = require('@vue/cli-service')
    const AutoImport = require("unplugin-auto-import/webpack");
    const Components = require("unplugin-vue-components/webpack");
    const { ElementPlusResolver } = require("unplugin-vue-components/resolvers");
    module.exports = defineConfig({
      transpileDependencies: true,
      configureWebpack: {
        plugins: [
          AutoImport({
            resolvers: [ElementPlusResolver()],
          }),
          Components({
            resolvers: [ElementPlusResolver()],
          }),
        ],
      },
    });
    
  4. 启动项目检验

    npm run serve
    

问题一:UI无法安装

如果Vs code安装UI组件库安装不了,是版本问题,在命令后面加上--legacy-peer-deps

问题二:启动项目报错

如果在启动检验项目的时候报错:

  1. ERROR TypeError: AutoImport is not a function

    unplugin-auto-import版本高了,降版本成0.16.7,这个问题就不报错了。

    npm install unplugin-auto-import@0.16.1 -force
    
  2. ERROR TypeError: Components is not a function

    unplugin-vue-components版本过高,回退插件版本。

     npm install unplugin-vue-components@0.25.2
    

如何查看是否生效呢?

我们可以在组件库里面引入几个按钮组件到Homeview.vue文件中,然后运行项目。组件按钮如果出现了就说明引入成功啦🥳🥳🥳

image-20240716175119148

引入按钮组件的代码:

<el-button>Default</el-button>
<el-button type="primary">Primary</el-button>
<el-button type="success">Success</el-button>
<el-button type="info">Info</el-button>
<el-button type="warning">Warning</el-button>
<el-button type="danger">Danger</el-button>

创建项目

Vue3.2新特性

下面我将介绍两个新特性:

第一个新特性就是不再需要

作为根目录。

在 Vue 3 中,特别是 Vue 3.2 版本,引入了一个新的 RFC (Request for Comments) 特性,即允许在单文件组件(SFC)的 <template> 中使用 <router-view> 作为根节点,而不再是必须使用 <div> 或其他元素作为根节点。这项特性是在 Vue Router 4 中实现的,它与 Vue 3 的 Composition API 和新的 <script setup> 语法糖相辅相成,提供了更灵活的路由视图设置。

这项改变允许开发者在 Vue 3 的单文件组件中这样写:

vue<template>
  <router-view/>
</template>

而不是必须将 <router-view> 包裹在一个 <div> 中:

vue复制<template>
  <div>
    <router-view/>
  </div>
</template>

第二个介绍的特性就是CSS可以直接绑定JS变量

在 Vue 3.2 版本中,引入了一项新特性,允许开发者直接在 CSS 中绑定 JavaScript 变量,这是通过 <style> 标签的 v-bind 属性实现的。这项特性特别适用于在使用 <script setup> 语法的单文件组件(SFC)中。

具体来说,你可以在 <style scoped><style module> 中使用 v-bind 来动态地应用 CSS 属性,这些属性的值可以是 JavaScript 表达式。例如:

vue<script setup>
import { ref } from 'vue';

const themeColor = ref('blue');
</script>

<template>
  <div :class="`color-${themeColor.value}`">Hello World</div>
</template>

<style scoped>
.color-blue {
  color: v-bind(themeColor);
}
</style>

在上面的示例中,color-blue 类的 color 属性会绑定到 themeColor 变量的值。当 themeColor 的值改变时,应用到 DOM 元素上的样式也会相应地更新。

初始化项目

先将App.vue文件里面一些没有用的文件和代码片段删掉。删完的代码如下:

<template>
  <router-view/>
</template>

<style lang="scss">

</style>

之后导入styles文件到项目中的src文件夹中,这个包包含了一些js的初始化操作以及一些Sass文件。

第三步在main.js当中导入index.scss文件。

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import '@/styles/index.scss'    //导入`index.scss`文件

createApp(App).use(store).use(router).mount('#app')

登录组件的实现

编写登录页面

  1. src下的views文件夹中创建一个login文件夹。并新建文件index.vue

  2. 在新建的文件书写一些内容

    <template>
        <div>
    			这是一个登录界面
        </div>
    </template>
    
    <script setup>
    
    </script>
    
    <style lang="scss" scoped>
    
    </style>
    
  3. 配置路由(转到srcrouter文件)

    //删掉后的文件内容
    // 路由配置文件
    import { createRouter, createWebHashHistory } from 'vue-router'
    const routes = [
      {
        //配置登录界面
        path: '/login',   //设置路径
        name: 'Login',    //设置名称
        component: () => import('../views/login/index.vue')     //导入文件
      }
    ]
    
    const router = createRouter({
      history: createWebHashHistory(),
      routes
    })
    
    export default router
    
  4. 删除以下👇这两个文件image-20240716220433842

如果这个时候发现出现了以下👇错误导致无法运行了:webpack compiled with 1 error

解决办法:

  1. 选中并打开"vue.config.js"

  2. 输入"lintOnSave:false"来关闭eslint校验

    lintOnSave:false
    
  1. 访问地址,因为是添加了路由,所以我们要在原来URL路径上添加login才能跳转到新添加的页面

    image-20240716221340707

编写页面

添加输入框

在登录页面文件中,引入一个表单组件

<template>
  <div class="login-container">
    <!-- 添加一个表单项 -->
    <el-form ref="form" :model="form" class="login-form">
        <div class="title-container">
            <h3 class="title">用户登录</h3>
        </div>
      <el-form-item>
        <el-input v-model="form.name"></el-input>
      </el-form-item>
    </el-form>
  </div>
</template>

创建双向数据绑定

<script setup>
  import { ref } from 'vue'
  const form = ref({
    name: ''
  })
</script>

添加图标

<template>
  <div class="login-container">
    <!-- 添加一个表单项 -->
    <el-form ref="formRef" :model="form" class="login-form">
      <div class="title-container">
        <h3 class="title">用户登录</h3>
      </div>
      <el-form-item>
        <!-- 添加图标 -->
        <el-icon :size="20" class="svg-container">
          <edit />
        </el-icon>
        <el-input v-model="form.username"></el-input>
      </el-form-item>
    </el-form>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import {Edit} from "@element-plus/icons-vue"		//添加图标
const form = ref({
  name: ''
})
</script>

回到界面中就能看到输入框和图标啦🥳image-20240716230059979

自定义图标
  1. 我们导入准备好的图标资源文件进入项目的src文件夹当中

  2. src/components文件夹下新建Svgicon文件夹,再新建一个index.vue文件。

  3. 定义新建文件

    <template>
    <svg class="svg-icon" aria-hidden="true">
        <use :xlink:href="iconName"></use>
    </svg>
    </template>
    
    <script setup>
    import { defineProps, computed } from 'vue'
    // eslint-disable-next-line no-unused-vars
    const props = defineProps({
        icon: {
            type: String,
            required: true
        }
    })
    // eslint-disable-next-line no-unused-vars
    const iconName = computed(() => {
      return `#icon-${props.icon}`
    })
    </script>
    
    <style lang="scss" scoped>
    .svg-icon {
      width: 1em;
      height: 1em;
      vertical-align: -0.15em;
      fill: currentColor;
      overflow: hidden;
    }
    </style>
    
    
    • aria-hidden的值为"true"表示屏幕阅读器会将该元素对于可访问性的处理视为隐藏,不会将其读取给用户听。这通常用于隐藏纯装饰性的图像或其他元素,以避免干扰屏幕阅读器用户。
    • <use :xlink:href="icon"></use> 它是SVG的一个功能,用于引用其他SVG元素,实现图标的重用。
    • fill: currentColor;: 这个属性用于指定 SVG 图标的填充颜色。currentColor 表示使用当前元素的文本颜色作为填充颜色。因此,该图标的颜色将与其所在的父元素的文本颜色一致
  4. 使用webpack获取到文件夹所有的文件,相当于批量获取上面svg文件夹里的图标导入。所以我们再新建一个src/icons/下面新建一个文件index.js文件,导入以下👇代码

    import SvgIcon from '@/components/SvgIcon'
    
    const svgRequired = require.context('./svg',false,/\.svg$/)
    svgRequired.keys().forEach((item) => svgRequired(item))
    
    export default (app) => {
        app.component('svg-icon',SvgIcon)
    }
    
  5. main.js中导入

    import { createApp } from 'vue'
    import App from './App.vue'
    import router from './router'
    import store from './store'
    import '@/styles/index.scss'
    import SvgIcon from '@/icons'
    
    const app = createApp(App)
    SvgIcon(app)
    app.use(store).use(router).mount('#app')
    
    
  6. 在项目终端中安装svg-loader

    npm i --save-dev svg-sprite-loader@6.0.9
    
  7. 配置webpack,的vue.config.js粘贴以下代码:(完全粘贴我的就可以了,以免导致不同)

    const AutoImport = require('unplugin-auto-import/webpack')
    const Components = require('unplugin-vue-components/webpack')
    const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
    
    const path = require('path')
    function resolve(dir) {
      return path.join(__dirname, dir)
    }
    const webpack = require('webpack')
    module.exports = {
      configureWebpack: config => {
        config.plugins.push(AutoImport({
          resolvers: [ElementPlusResolver()],
        }))
        config.plugins.push(Components({
          resolvers: [ElementPlusResolver()],
        }))
      },
      chainWebpack(config) {
        // 设置 svg-sprite-loader
        // config 为 webpack 配置对象
        // config.module 表示创建一个具名规则,以后用来修改规则
        config.module
          // 规则
          .rule('svg')
          // 忽略
          .exclude.add(resolve('src/icons'))
          // 结束
          .end()
        // config.module 表示创建一个具名规则,以后用来修改规则
        config.module
          // 规则
          .rule('icons')
          // 正则,解析 .svg 格式文件
          .test(/\.svg$/)
          // 解析的文件
          .include.add(resolve('src/icons'))
          // 结束
          .end()
          // 新增了一个解析的loader
          .use('svg-sprite-loader')
          // 具体的loader
          .loader('svg-sprite-loader')
          // loader 的配置
          .options({
            symbolId: 'icon-[name]'
          })
          // 结束
          .end()
        config
          .plugin('ignore')
          .use(
            new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn$/)
          )
        config.module
          .rule('icons')
          .test(/\.svg$/)
          .include.add(resolve('src/icons'))
          .end()
          .use('svg-sprite-loader')
          .loader('svg-sprite-loader')
          .options({
            symbolId: 'icon-[name]'
          })
          .end()
        }
    }
    

之后就是使用新建的组件,我们用下面的语句替换上面讲的添加图标内容:

<svg-icon icon="username" class="svg-container"></svg-icon>
<svg-icon icon="password" class="svg-container"></svg-icon>

<script setup>
import { ref } from 'vue'
// import { Edit } from '@element-plus/icons-vue' 还需要注释掉不用的edit
</script>

添加密码框

下面是添加密码框,做法也是和上面一样的,我们直接复制上面写好的图标和输入框代码

<!-- 下面是密码框 -->
      <el-form-item>
        <!-- 添加图标 -->
        <svg-icon icon="user" class="svg-container"></svg-icon>
        <el-input v-model="form.password"></el-input>
        <!-- 注意这里将绑定值改成密码password -->
      </el-form-item>
    
  <script setup>
    import { ref } from 'vue'
    import { Edit } from "@element-plus/icons-vue"
    const form = ref({
      username: '',
      password: ''  //注入password
    })
  </script>

添加按钮

<el-button type="primary" class="login-button">点击登录</el-button>

添加样式

注意:这个样式up没有带敲,所有大家就直接拿过来用吧(*´▽`)ノノ。

$bg: #2d3a4b;
$dark_gray: #889aa4;
$light_gray: #eee;
$cursor: #fff;

.login-container {
  min-height: 100%;
  width: 100%;
  background-color: $bg;
  overflow: hidden;

  .login-form {
    position: relative;
    width: 520px;
    max-width: 100%;
    padding: 160px 35px 0;
    margin: 0 auto;
    overflow: hidden;

    ::v-deep .el-form-item {
      border: 1px solid rgba(255, 255, 255, 0.1);
      background: rgba(0, 0, 0, 0.1);
      border-radius: 5px;
      color: #454545;
    }

    ::v-deep .el-input {
      display: inline-block;
      height: 47px;
      width: 85%;

      input {
        background: transparent;
        border: 0px;
        -webkit-appearance: none;
        border-radius: 0px;
        padding: 12px 5px 12px 15px;
        color: $light_gray;
        height: 47px;
        caret-color: $cursor;
      }
    }
    .login-button {
      width: 100%;
      box-sizing: border-box;
    }
  }

  .tips {
    font-size: 16px;
    line-height: 28px;
    color: #fff;
    margin-bottom: 10px;

    span {
      &:first-of-type {
        margin-right: 16px;
      }
    }
  }

  .svg-container {
    padding: 6px 5px 6px 15px;
    color: $dark_gray;
    vertical-align: middle;
    display: inline-block;
  }

  .title-container {
    position: relative;

    .title {
      font-size: 26px;
      color: $light_gray;
      margin: 0px auto 40px auto;
      text-align: center;
      font-weight: bold;
    }

    ::v-deep .lang-select {
      position: absolute;
      top: 4px;
      right: 0;
      background-color: white;
      font-size: 22px;
      padding: 4px;
      border-radius: 4px;
      cursor: pointer;
    }
  }

  .show-pwd {
    // position: absolute;
    // right: 10px;
    // top: 7px;
    font-size: 16px;
    color: $dark_gray;
    cursor: pointer;
    user-select: none;
  }
}

最后就实现了整个页面啦🥳

image-20240717173234398

报错问题汇总

补充:如果在重启项目的时候报错,这个时候就需要重新安装一遍UI组件。

npm install --save element-plus

如果出现了以下问题:

  1. error ‘_‘ is defined but never used no-unused-vars

    • 在前面加一行注释:(表示忽略下一行校验)

      // eslint-disable-next-line
      
  2. error ‘xxx‘ is assigned a value but never used

    • 在前面加一行注释:(通常表示你给一个变量赋了值,但在代码中没有使用它)

      // eslint-disable-next-line no-unused-vars
      
  3. error Newline required at end of file but not found eol-last

    • 这里有了格式冲突问题,最后应该加一行空行就行(最后想吐槽一下eslint要求太严格了😨)例如:image-20240717163955922
  4. Expected space or tab after ‘//‘ in comment.(spaced-comment)这个也一样是少了空格,就是在双斜杠//后面还要添加一个空格才行。

    • 例如:// 先空格,然后再接内容
      

实现登录功能

表单验证

Form 表单 | Element Plus (element-plus.org)转到表单验证一栏中,image-20240717173951928

这个rules就是使用规则,我们复制他并粘贴到<el-form>标签上,如下:

<el-form ref="formRef" :model="form" class="login-form" :rules="rules">

之后定义校验规则:

const rules = ref({
  username: [
    {
      // 必填项
      required: true,
      // 提示语
      message: 'Please input Activity name',
      // 触发条件方式
      trigger: 'blur'
    }
  ],
  password: [
  {
      required: true,
      message: 'Please input Activity name',
      trigger: 'blur'
    }
  ]
})

form-item标签上绑定检验规则:

<el-form-item prop="username">
<el-form-item prop="password">
实现统一校验

这里特别声明一下:校验规则不需要响应式,因为校验规则没有状态变化。所以我们只需要再添加一个点击事件,触发到登录按钮即可实现。

给按钮添加一个点击事件,并定义了一个handleLogin方法:

<el-button type="primary" class="login-button" @click="handleLogin">点击登录</el-button>

定义方法:

const formRef = ref(null)
const handleLogin = () => {
  formRef.value.validate((valid) => {
    if (valid) {
      alert('submit!')
    } else {
      console.log('error submit!!')
      return false
    }
  })
}

检验方法,打开我们的项目,点击登录按钮,如果弹出提示语就说明应用正确✔️了

image-20240717183951879

登录请求

src下新建一个api文件夹然后再创建一个request.js文件。

  1. 导入axios
import axios from "axios"
  1. 创建axios基础配置
import axios from 'axios'
// eslint-disable-next-line
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  timeout: 5000
})

export default service

因为我们有开发环境和生产环境,所以我们要在根目录下面创建:开发环境.env.development和生产环境.env.production

//.env.development文件中添加代码
ENV = 'development'

VUE_APP_BASE_API = '/api'

//.env.production文件中添加代码
ENV = 'production'

VUE_APP_BASE_API = '/prod-api'

在vue.config.js配置代理来解决跨越问题

devServer: {
    https: false,
    hot: false,
    proxy: {
      '/api': {
        target: 'https://lianghj.top:8888/api/private/v1/',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }

在api文件夹中新建一个login.js文件用来发起post请求。

import request from './request'

export const login = (data) => {
  return request({
    url: '/login',
    method: 'POST',
    data
  })
}

回到登录页面,导入登录方法

import { login } from '@/api/login'

在登录校验方法中添加登录触发方法:

const formRef = ref(null)
const handleLogin = () => {
  formRef.value.validate(async (valid) => {
    if (valid) {
      // alert('submit!')
      await login(form.value)
    } else {
      console.log('error submit!!')
      return false
    }
  })
}
密码隐藏

ElementPlus 自带切换功能 <el-input type="password" show - password /> 即可

<el-input type="password" show-password/>

响应拦截器

响应拦截器是一种编程技术,通常在网络请求库中使用。它允许开发者在服务器响应返回给应用程序之前,对响应数据进行处理或修改。这可以用于日志记录、错误处理、数据验证、修改响应内容等目的。

例如,在JavaScript的Axios库中,可以通过配置响应拦截器来处理HTTP响应。这样,无论请求成功还是失败,都可以统一处理响应数据。

  1. 定义res接受数据
const handleLogin = () => {
  formRef.value.validate(async (valid) => {
    if (valid) {
      // alert('submit!')
      const res = await login(form.value)// 添加一个res接受传递过来的数据
      console.log(res)// 反馈
    } else {
      console.log('error submit!!')
      return false
    }
  })
}
  1. request.js文件添加响应请求拦截器

    service.interceptors.response.use(
      (response) => {
        const { data, meta } = response.data
        if (meta.status === 200 || meta.status === 201) {
          return data
        } else {
          ElMessage.error(meta.msg)
          return Promise.reject(new Error(meta.msg))
        }
      },
      (error) => {
        console.log(error.response)
        error.response && ElMessage.error(error.response.data)
        return Promise.reject(new Error(error.response.data))
      }
    )
    
    //request.js完整代码
    import axios from 'axios'
    import { ElMessage } from 'element-plus'
    import { diffTokenTime } from '@/utils/auth'
    import store from '@/store'
    const service = axios.create({
      baseURL: process.env.VUE_APP_BASE_API,
      timeout: 5000
    })
    
    service.interceptors.request.use(
      (config) => {
        if (localStorage.getItem('token')) {
          if (diffTokenTime()) {
            store.dispatch('app/logout')
            return Promise.reject(new Error('token 失效了'))
          }
        }
        config.headers.Authorization = localStorage.getItem('token')
        return config
      },
      (error) => {
        return Promise.reject(new Error(error))
      }
    )
    
    service.interceptors.response.use(
      (response) => {
        const { data, meta } = response.data
        if (meta.status === 200 || meta.status === 201) {
          return data
        } else {
          ElMessage.error(meta.msg)
          return Promise.reject(new Error(meta.msg))
        }
      },
      (error) => {
        console.log(error.response)
        error.response && ElMessage.error(error.response.data)
        return Promise.reject(new Error(error.response.data))
      }
    )
    export default service
    
    
  2. 改正报错样式

在我们密码错误的时候,报错的样式却不是我们意料当中的弹窗提醒.那是因为我们的UI组件库样式还没有导入.

将一下代码导入带到main.js当中:

import 'element-plus/dist/index.css'

这样密码错误样式就成功啦!!!

image-20240717233226664

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2047822.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Navicat Premium Lite For Linux,一款免费的专业可视化 SQL 数据库设计工具,支持各种数据库并行连接,在业界可是大名鼎鼎!

Navicat Premium Lite For Linux&#xff0c;一款免费的专业可视化 SQL 数据库设计工具&#xff0c;支持各种数据库并行连接&#xff0c;在业界可是大名鼎鼎&#xff01; Navicat 是一个可视化数据库、数据表设计软件&#xff0c;支持MySQL、MariaDB、SQLite、MongoDB、Redshi…

论文阅读笔记:ST-MetaNet-1

目录 前言 摘要 CCS 关键词 介绍 时空相关性的复杂组合 空间相关性 时间相关性 时空相关性的多样性 本篇博客结语 前言 读这篇论文边读边学&#xff0c;每天坚持发博客&#xff0c;看到哪学到哪&#xff0c;这系列文章既有翻译&#xff0c;又有深度详细解释&#xff…

Rust学习笔记1--下载安装和使用

一、下载和安装&#xff1a; 官网&#xff1a;https://www.rust-lang.org/ 直接下载即可&#xff0c;windows&#xff1a;按照教程执行步骤。 二、使用&#xff1a; 2.1 在vscode中安装rust 2.2 编译与运行rust文件&#xff1a; 后缀名rs&#xff1a; 编译&#xff1a; …

org.springframework.boot.autoconfigure.AutoConfiguration.imports 配置没有生效

在spring3.x以后&#xff0c;自动配置需要配置在org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中 如果你配置了却没生效&#xff0c;有可能是创建的目录不对&#xff0c;正常情况下, META-INF.spring 是一个两层目录&#xff0c;如果是从别的地方复制…

第51集《大佛顶首楞严经》

请大家打开讲义第 111 页。癸三&#xff0c;结责迷情。 当我们在修学首楞严王三昧的时候&#xff0c;要把握两个很重要的原则&#xff1a;第一个就是它修学的方法&#xff0c;第二个就是它修学的目标。 那么&#xff0c;首楞严王的修学方法是什么呢&#xff08;这一点蕅益大师…

零基础读懂 DDPM 数学推导

零基础读懂 DDPM 数学推导 完整PDF文件可以在工坊获得&#xff0c;以下是内容截图。

为何显示keyerror fruit,如何解决??

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…

【docker综合篇】关于我用docker搭建了6个应用服务的事

最近一直在捣鼓docker&#xff0c;利用测试服务器&#xff0c;本着犯错就重来(重装系统)的大无畏精神&#xff0c;不断尝试&#xff0c;总结经验&#xff0c;然后在网上搜寻一些关于docker有关的服务镜像&#xff0c;并搭建起来。看着一个个服务在我的服务器跑起来&#xff0c;…

【QT】基于UDP/TCP/串口 的Ymodom通讯协议客户端

【QT】基于UDP/TCP/串口的Ymodom通讯协议客户端 前言Ymodom实现QT实现开源库的二次开发-1开源库的二次开发-2 串口方式实现TCP方式实现UDP方式实现补充&#xff1a;文件读取补充&#xff1a;QT 封装成EXE 前言 Qt 运行环境 Desktop_Qt_5_11_2_MSVC2015_64bit &#xff0c;基于…

PowerShell自动化Windows系统管理任务

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言 Windows系统管理涉及许多繁琐的任务&#xff0c;如用户管理、文件操作、系统更新、网络配置等。PowerShell作为Windows的命令行工具和脚本语言&#xff0c;可以极大地简化这些管理任务。本文将探讨如何使用PowerShell自动…

【教学类-75-01】20240817“通义万相图片最大化+透明png”的修图流程

背景需求&#xff1a; 打印了袜子配对的PDF模版&#xff0c;做预测试 【教学类-74-02】彩色袜子配对02--左右配对-CSDN博客文章浏览阅读497次&#xff0c;点赞10次&#xff0c;收藏9次。【教学类-74-02】彩色袜子配对02--左右配对https://blog.csdn.net/reasonsummer/article…

09:链表的介绍

链表 1、算法的定义2、链表 1、算法的定义 通俗的定义&#xff1a;解题的方法与步骤。       狭义的定义&#xff1a;对存储的数据的操作。       广义的定义&#xff1a;无论数据是如何存储的&#xff0c;对数据从操作都是一样的。 到目前为止我们可以通过2种结构来存储…

关于订单最终一致性解决方案

背景 整体的交易架构主要由两部分组成&#xff1a;C端交易平台 - B端交易平台 由于组织架构的特殊性&#xff0c;并没有采用两阶段提交、三阶段提交这种刚性分布式事务的方案。 主要采用了基于TCC思想的TOC柔性事务补偿方案。 柔性事务&#xff1a;遵循BASE原则&#xff0c;…

Redis7.x安装系列教程(四)集群部署原理详解

1、什么是集群部署 Redis集群(cluster)是Redis的一种分布式运行模式&#xff0c;通过分片(sharding)提供数据的自动分区和管理&#xff0c;实现数据的高可用性和可扩展性。 在集群模式下&#xff0c;数据分布在多个Redis节点上&#xff0c;节点分为主节点和从节点。主节点负责…

Pytorch如何判断两个模型的权重是否相同(比较权重差异/参数字典)

参考资料&#xff1a; GPT-4o mini的回答 第一种方法是使用md5sum这个命令(Linux上)&#xff0c;但是由于环境的不同&#xff0c;哪怕是load之后转存似乎都会有差&#xff0c;所以效果不大。 第二种方法是使用代码比较&#xff0c;这段代码是我找GPT要的&#xff0c;感觉非常不…

Linux线程间通信学习记录(线程同步)

0.线程间通信的方法 &#xff08;1&#xff09;.全局变量&#xff08;要结合同步机制&#xff09; &#xff08;2&#xff09;.信号量 &#xff08;3&#xff09;.P操作 &#xff08;4&#xff09;.V操作 一.线程同步 同步&#xff1a;指的是多个任务按照约定的先后次序相互…

OpenCV图像滤波(19)计算图像每个像素点的邻域内的平方和函数sqrBoxFilter()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 计算覆盖在滤波器上的像素值的平方和。 对于源图像中的每一个像素 (x, y)&#xff0c;函数计算那些与放置在像素 (x, y) 上的滤波器重叠的邻域像…

【百度】25届秋招内推码

内推码 IV1RBB 介绍 &#x1f4e3; 百度TPG技术中台事业群组—深度学习技术平台部 25届校招正在进行中&#xff0c;可通过定向内推形式get校招绿色通道 &#xff01; 欢迎联系我定向内推 &#x1f31f;【部门介绍】 飞桨&#xff08;PaddlePaddle&#xff09;以百度多年的深度…

坐牢第二十七天(聊天室)

基于UDP的网络聊天室 一.项目需求&#xff1a; 1.如果有用户登录&#xff0c;其他用户可以收到这个人的登录信息 2.如果有人发送信息&#xff0c;其他用户可以收到这个人的群聊信息 3.如果有人下线&#xff0c;其他用户可以收到这个人的下线信息 4.服务器可以发送系统信息…

idea 遇到依赖引入失败问题

在引入 aspects 的相关依赖时&#xff0c;没有找到这个版本 <dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.0.0-M2</version> </dependency> 第一次尝试&#xff…