VUE3+vite+arco design 项目初始化

发布时间 2023-09-22 09:54:56作者: 分页需带参

意见反馈系统总结

创建项目

首先选择一个文件夹

进入命令窗口

使用vite创建项目

npm create vite@latest

初始化项目后

进入项目安装依赖

npm install

运行

npm run dev

使用arcodesign组件库

安装

npm install --save-dev @arco-design/web-vue

引入

import { createApp } from 'vue'
import ArcoVue from '@arco-design/web-vue';
import App from './App.vue';
import '@arco-design/web-vue/dist/arco.css';

const app = createApp(App);
app.use(ArcoVue);
app.mount('#app');

安装路由

npm install vue-router@4

导入

import router from './router'

安装tailwind

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
//tailwind.config.js

/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{vue,js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
//style.css

@tailwind base;
@tailwind components;
@tailwind utilities;

导入

import './styles/index.css'

![img](file:///C:/Users/iot/Documents/WXWork/1688857687511455/Cache/Image/2023-09/企业微信截图_16945949474256.png)

配置路由

主路由

import { createRouter, createWebHashHistory } from "vue-router";

import layout from "@/layout/index.vue";
import baseRoute from "./modules/baseManagement.js";
import postsManagement from "./modules/postsManagement.js";
import productManagement from "./modules/productManagement.js";
import userManagement from "./modules/userManagement.js";

//得到sessionStorage中的userRole
//1 超级管理员 2 管理员 3 普通用户
const userRole = sessionStorage.getItem("userRole");

//管理员路由
//一级路由
const routes = [
  {
    path: "/login",
    name: "Login",
    component: () => import("@/views/login/index.vue"),
    children: [],
  },
  {
    path: "/403",
    name: "403",
    meta: {
      title: "没有权限",
      showLink: false,
      roles:['admin','user']
    },
    component: () => import("../views/error/403.vue"),
  },
  {
    path: "/404",
    name: "404",
    meta: {
      title: "找不到页面",
      showLink: false,
      roles:['admin','user']
    },
    component: () => import("../views/error/404.vue"),
  },
  {
    path: "/",
    name: "基础管理",
    redirect: '/baseManagement/user',
    component: layout,
    meta: {
      title: "基础管理",
      showLink: true,
      icon:'tdesign:app',
      roles:['admin','user']
    },
    //二级路由
    children: [...baseRoute, ...userManagement],
  },
  {
    path: "/productManagement",
    name: "商品管理",
    component: layout,
    meta: {
      title: "商品管理",
      showLink: true,
      icon:'fluent-mdl2:product-variant',
      roles:['admin']
    },
    children: [...productManagement],
  },
  {
    path: "/postsManagement",
    name: "意见管理",
    
    component: layout,
    meta: {
      title: "意见管理",
      showLink: true,
      icon:'teenyicons:bulb-on-outline',
      roles:['admin','user']
    },
    children: [...postsManagement],
  },
];

const router = createRouter({
  history: createWebHashHistory(),
  routes: routes,
});

export default router;

子路由

//基础管理路由配置
const routes =  [
      {
        path: '/welcome',
        name: 'welcome',
        component: () => import('@/views/baseManagement/welcome.vue'),
        meta: {
          title: "欢迎页面",
          roles:['admin','user']
        },
        children: []
      },
      {
        path:'/baseManagement/user/:page?',
        name:'user',
        component:()=> import('@/views/baseManagement/user/index.vue'),
        meta: {
          title: "用户列表",
          showLink: true,
          icon:'ant-design:usergroup-add-outlined',
          roles:['admin','user']
        },
        children:[]
      },
      {
        path:'/baseManagement/admin/:page?',
        name:'admin',
        component:()=> import('@/views/baseManagement/admin/index.vue'),
        meta: {
          title: "管理员列表",
          showLink: true,
          icon:'solar:user-linear',
          roles:['admin']
        },
        children:[]
      },
      {
        path:'/baseManagement/theme/:page?',
        name:'theme',
        component:()=> import('@/views/baseManagement/theme/index.vue'),
        meta: {
          title: "主题列表",
          showLink: true,
          icon:'ant-design:skin-outlined',
          roles:['admin']
        },
        children:[]
      },
      {
        path:'/baseManagement/compliance/:page?',
        name:'compliance',
        component:()=> import('@/views/baseManagement/compliance/index.vue'),
        meta: {
          title: "公告管理",
          showLink: true,
          icon:'ant-design:sound-outlined',
          roles:['admin']
        },
        children:[]
      } 
    ]

    export default routes
  

导航守卫

操作路由跳转做的事情

import router from "./router"
/**
 * 路由前置守卫
 */

//从sso拿token的方法
const getQueryVariable = (variable) => {
    // console.log(window.location.href.split('?')[0])
    if (window.location.href.indexOf('?') > -1) {
      let query = window.location.href.split('?')[1]
      let vars = query.split('&')
      for (var i = 0; i < vars.length; i++) {
        var pair = vars[i].split('=')
        if (pair[0] == variable) {
          return pair[1]
        }
      }
      return false
    } else {
      return false
    }
  }


router.beforeEach(async (to, from, next) => {
    
    if (getQueryVariable('token')) {
      sessionStorage.setItem('token', getQueryVariable('token'))
      console.log(funcUrlDel())
      history.pushState('', '', funcUrlDel())
      console.log('9999')
    }
    
    if (sessionStorage.getItem('token')) {
      //得到sessionStorage中的userRole
      const userRole = sessionStorage.getItem("userRole")?sessionStorage.getItem("userRole"):'';

      //分权限进入不同的菜单
      //如果进入路由中有权限to.meta.roles.includes(userRole)  在路由中配置的  roles:['admin','user']
      if(to.meta.hasOwnProperty('roles') && to.meta.roles.includes(userRole)){
          //如果访问的是登录页面,但是有token了,直接跳转到主页面
        if (to.path === '/login') {
          next('/')
           // 如果访问的路由未在路由中配置,直接跳转404页面
        }else if (!to.name) {
          next("/404")
           //访问404或者403 放行
        } else if (to.path == "/404" || to.path == "/403") {
          next()
        }else {
          next()
        }
      //如果路由中没有权限,直接404
      }else{
        next("/404")
        
      }


     
    } else {
      // 没有token的情况下,可以进入白名单
        if (to.path === '/login' || to.path === '/404' || to.path === '/403') {
            next()
        } else {
            next('/login')
        }
    }
  })

API请求axios拦截

//get请求
 export const getFileData = (data) => {
     return http({
         url: '/File/getFileInfo',
         params: data
     })
 }
//post请求
export const getFileData = data => {
    return http({
        url: '/File/getFileInfo',
        method: 'POST',
        data
    })
}

axios请求拦截

需要安装axios

import axios from 'axios'

import { Message } from "@arco-design/web-vue";



const service = axios.create({
  baseURL: '/apiUrl',
  // baseURL: 'http://iot-bbs.yangzijiang.com/',
  timeout: 5000
})

//响应拦截器
service.interceptors.response.use(
  (response) => {
  if (response.status === 200) {
    return response.data
  } else if (response.status === 401) {
    console.log('401')
  } else {
    return Promise.reject(new Error(response.status))
  }
},
    //如果token过期了,则将storage中的数据清理了,需要重新登录
error=>{
  if(error.message && error.message.indexOf('401') > -1){
    Message.error('请重新登录!')
    sessionStorage.clear()
    location.reload();
  }
})

// 请求拦截
service.interceptors.request.use(
  (config) => {
    if (sessionStorage.getItem('token')) {
      config.headers.Authorization = `Bearer ` + sessionStorage.getItem('token')
    } else {
    }
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)


export default service

登陆成功存取token

请求成功后存token至session Storage

 //请求成功将数据存入sessionStorage
  //1 管理员 2  普通用户
        if (resgetrole.resstr == "1") {
          sessionStorage.setItem("userRole", "admin");
        } else {
          sessionStorage.setItem("userRole", "user");
        }
    sessionStorage.setItem("token", res.resStr);
    sessionStorage.setItem("phone", loginForm.value.phone);
    router.push("/");

//拿到sessionStorage中的phone
const token = sessionStorage.getItem("token");

清除缓存

//退出登录
const handleLogout = () => {
  sessionStorage.removeItem("token");
  location.reload();
};

通用工具utils

组件通信工具bus

// 先定义一个类型,emit作为发布(传递),on作为订阅(接收)
// name是事件名称,callback是一个回调函数
type BusClass = {
    emit:(name:string) => void
    on:(name:string, callback:Function) => void
}
// 定义多种参数类型
type PramsKey = string | number | symbol
// 定义一个调用中心,可以接收多个参数
type List = {
   [key:PramsKey]: Array<Function>
}
class Bus implements BusClass {
    list: List
    constructor (){
        // 初始化list
        this.list = {}   
    }
    // 发布事件,...args解构多个参数
    emit (name:string,...args:Array<any>){
        // 获取到list里的数据
        let evnentName:Array<Function> = this.list[name]
        evnentName.forEach(fn =>{
            fn.apply(this, args)
        })
    }
    // 接收事件
    on (name:string, callback:Function){
        // 如果是第一次注册,则为空;如果被多次注册,则采用之前注册的名字
        let fn:Array<Function> = this.list[name] || []
        fn.push(callback)
        this.list[name] = fn
    }
}
// 导出bus
export default new Bus()

使用

//触发  updateUserData标识
Bus.emit("updateUserData", 1);


//执行
Bus.on("updateUserData", (str) => {
  	console.log(str);
  	getUserList();
});

响应式布局

import { OLD_SCREEN_WIDTH } from "../constants";

//对电脑不同分辨率

export const isOldScreen = () => {
    return window.outerWidth > OLD_SCREEN_WIDTH ? "medium" : "mini";
  };

  export const isOldButton = () => {
    return window.outerWidth > OLD_SCREEN_WIDTH ? "20" : "13";
  };
  
  export const isOldTable = () => {
    return window.outerWidth > OLD_SCREEN_WIDTH ? 580 : 320;
  };

工程化思想

先构思好页面布局,可以组件化的都要组件化,比如Tags、Search、Table、Options;用好状态管理工具,否则使用bus