意见反馈系统总结
创建项目
首先选择一个文件夹
进入命令窗口
使用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
标签:vue,name,sessionStorage,token,design,VUE3,import,path,arco From: https://www.cnblogs.com/sxliu414/p/17721609.html