当前位置: 首页 > wzjs >正文

书店网站模板下载微营销工具有哪些

书店网站模板下载,微营销工具有哪些,动漫网站建设赚钱吗,做企业网站制作目录 一、前言 二、后端调整 1.实体类调整 2.菜单相关接口 3.用户相关接口 4.新增工具类 5.新增菜单树返回类 6.配置类、拦截器 三、前端调整 1.请求调整 2.页面布局、样式调整 1.user.vue 2.index.vue 3.请求拦截 四、开发过程中的问题 五、附&#xff1a…

目录

一、前言

二、后端调整 

1.实体类调整

2.菜单相关接口

3.用户相关接口

4.新增工具类

5.新增菜单树返回类

6.配置类、拦截器 

三、前端调整

1.请求调整

2.页面布局、样式调整

1.user.vue 

2.index.vue 

3.请求拦截

四、开发过程中的问题

五、附:源码

1.源码下载地址

六、结语

一、前言

此文章在上次的基础上进行了部分调整,并根据用户体验(我自己)确认了页面整体布局和数据呈现,暂定就先这样,后续有需要或者有不协调的地方再调整。
此项目是在我上一个文章的后续开发, 需要的同学可以关注一下,文章链接如下:SpringBoot+Mybatis+MySQL+Vue+ElementUI前后端分离版:项目搭建(一)

(注:源码我会在文章结尾提供gitee连接,需要的同学可以去自行下载)

二、后端调整 

1.实体类调整

1.完善UserEntity.java


import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;import java.util.Date;@Data
public class UserEntity extends BaseEntity{/*** id 主键*/private Integer id;/*** name 姓名*/private String name;/*** age 年龄*/private Integer age;/*** birthday 生日*/@JsonFormat(pattern = "yyyy-MM-dd")@DateTimeFormat(pattern = "yyyy-MM-dd")private Date birthday;}

2.新增菜单实体类MenuEntity.java


import lombok.Data;/*** 菜单表* @TableName menu*/
@Data
public class MenuEntity extends BaseEntity {/*** 主键*/private Integer id;/*** 菜单名称*/private String menuName;/*** 父菜单ID*/private Integer parentId;/*** 路由路径*/private String path;/*** 组件路径*/private String component;/*** 权限标识*/private String perms;/*** 图标*/private String icon;/*** 排序*/private Integer sort;/*** 是否显示(0隐藏,1显示)*/private Integer visible;}

这里在数据库新建menu表,并添加几条测试数据。

CREATE TABLE `menu` (`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',`menu_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单名称',`parent_id` int DEFAULT '0' COMMENT '父菜单ID',`path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '路由路径',`component` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '组件路径',`perms` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '权限标识',`icon` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '图标',`sort` int DEFAULT '0' COMMENT '排序',`visible` tinyint(1) DEFAULT '1' COMMENT '是否显示(0隐藏,1显示)',`create_time` datetime DEFAULT NULL COMMENT '创建时间',`create_by` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',`update_time` datetime DEFAULT NULL COMMENT '更新时间',`update_by` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人',`del_flag` int(10) unsigned zerofill DEFAULT '0000000000' COMMENT '删除标识0未删除,1已删除',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='菜单表';
-- 插入数据
INSERT INTO `menu` (id, menu_name, parent_id, path, component, perms, icon, sort, visible, create_time, create_by, update_time, update_by, del_flag)
VALUES
(1, '权限管理', 0, '/permission', '', '', 'lock', 1, 1, NOW(), 'admin', NULL, NULL, 0),(2, '用户管理', 1, '/user', 'src/view/user.vue', 'user:list', 'user', 1, 1, NOW(), 'admin', NULL, NULL, 0),(3, '角色管理', 1, '/role', 'src/view/role.vue', 'role:list', 'role', 2, 1, NOW(), 'admin', NULL, NULL, 0),(4, '菜单管理', 1, '/menu', 'src/view/menu.vue', 'menu:list', 'menu', 3, 1, NOW(), 'admin', NULL, NULL, 0);

 3.对于实体类公共字段,我提取了一个BaseEntity.java,后续实体类都继承此实体类。

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;import java.util.Date;/*** 实体类公共字段* @Author: wal* @Date: 2025/6/26*/
@Data
public class BaseEntity {/*** 创建时间*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date createTime;/*** 创建人*/private String createBy;/*** 修改时间*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date updateTime;/*** 修改人*/private String updateBy;/*** 删除标记0未删除1已删除(逻辑删除)*/private Integer delFlag;}

2.菜单相关接口

1.MenuController.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.wal.userdemo.DTO.resp.TreeDataResp;
import org.wal.userdemo.service.MenuService;
import org.wal.userdemo.utils.Result;import java.util.List;@RestController
@RequestMapping("/api/menu")
public class MenuController {@Autowiredprivate MenuService menuService;@GetMapping("/getMenuList")public Result<List<TreeDataResp>> getMenuList() {return Result.success(menuService.getMenuList(""));}
}

2.MenuService.java

import org.wal.userdemo.DTO.resp.TreeDataResp;import java.util.List;public interface MenuService {List<TreeDataResp> getMenuList(String  userId);
}

 3.MenuServiceImpl.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.wal.userdemo.DTO.resp.TreeDataResp;
import org.wal.userdemo.entity.MenuEntity;
import org.wal.userdemo.mapper.MenuMapper;
import org.wal.userdemo.service.MenuService;
import org.wal.userdemo.utils.BeanUtils;import java.util.*;@Service
public class MenuServiceImpl implements MenuService {@Autowiredprivate MenuMapper menuMapper;/*** 获取用户菜单列表* @param userId* @return*/@Overridepublic List<TreeDataResp> getMenuList(String userId) {List<MenuEntity> menuList = menuMapper.getMenuList(userId);List<TreeDataResp> treeDataRespList =BeanUtils.copyAsList(menuList, TreeDataResp.class);return buildMenuTree(treeDataRespList);}/*** 构建菜单树* @param menus* @return*/public List<TreeDataResp> buildMenuTree(List<TreeDataResp> menus) {Map<Integer, TreeDataResp> menuMap = new HashMap<>();menus.forEach(menu -> menuMap.put(menu.getId(), menu));List<TreeDataResp> rootMenus = new ArrayList<>();menus.forEach(menu -> {Integer parentId = menu.getParentId();if (parentId == null || parentId == 0) {rootMenus.add(menu);} else {TreeDataResp parent = menuMap.get(parentId);if (parent != null) {if (parent.getChildren() == null) {parent.setChildren(new ArrayList<>());}parent.getChildren().add(menu);}}});return rootMenus;}}

 4.MenuMapper.java

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.wal.userdemo.entity.MenuEntity;import java.util.List;/**
* @author Administrator
* @description 针对表【menu(菜单表)】的数据库操作Mapper
* @createDate 2025-07-07 00:12:30
* @Entity org.wal.userdemo.entity.Menu
*/
@Mapper
public interface MenuMapper {List<MenuEntity> getMenuList(@Param("userId") String  userId);}

5.MenuMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.wal.userdemo.mapper.MenuMapper"><resultMap id="BaseResultMap" type="org.wal.userdemo.entity.MenuEntity"><id property="id" column="id" /><result property="menuName" column="menu_name" /><result property="parentId" column="parent_id" /><result property="path" column="path" /><result property="component" column="component" /><result property="perms" column="perms" /><result property="icon" column="icon" /><result property="sort" column="sort" /><result property="visible" column="visible" /><result property="createTime" column="create_time" /><result property="createBy" column="create_by" /><result property="updateTime" column="update_time" /><result property="updateBy" column="update_by" /><result property="delFlag" column="del_flag" /></resultMap><select id="getMenuList" parameterType="String" resultMap="BaseResultMap">SELECT * FROM menu WHERE del_flag = 0 ORDER BY parent_id, sort;</select></mapper>

3.用户相关接口

1.UserController.java

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;
import org.wal.userdemo.DTO.req.QueryUserReq;
import org.wal.userdemo.entity.UserEntity;
import org.wal.userdemo.service.UserService;
import org.wal.userdemo.utils.Result;import java.util.List;@Slf4j
@RestController
@RequestMapping("/api/user")
public class UserController {@Autowiredprivate UserService userService;/*** 获取所有用户信息** @return List<UserEntity>*/@PostMapping("/getUserList")public Result<UserEntity> getUserList(@RequestBody QueryUserReq queryUserReq) {List<UserEntity> dataList = userService.getUserList(queryUserReq);Integer total = userService.getUserCount(queryUserReq);return Result.page(dataList, total);}
}

2.定义通用分页Result.java(前文已体现,只是新增一个分页构造函数)

   public static <T> Result<T> page(List<T> list, Integer total) {Result<T> result = new Result<>();result.setCode(200);result.setData(list);result.setTotal(total);result.setMessage("success");return result;}

 3.UserService.java(新增两个接口)

    /*** 查询所有用户** @return*/List<UserEntity> getUserList(QueryUserReq queryUserReq);/*** 查询用户数量** @return*/Integer getUserCount(QueryUserReq queryUserReq);

4.UserServiceImpl.java(新增两个实现方法)

    /*** 获取所有用户信息** @return List<UserEntity>*/@Overridepublic List<UserEntity> getUserList(QueryUserReq queryUserReq) {List<UserEntity> resp = userMapper.getUserList(queryUserReq);return resp;}/*** 获取用户数量** @return Integer*/@Overridepublic Integer getUserCount(QueryUserReq queryUserReq) {return userMapper.getUserCount(queryUserReq);}

5.UserMapper.java(新增两个mapper接口)

/*** 查询所有用户** @return*/List<UserEntity> getUserList(QueryUserReq queryUserReq);/*** 查询用户数量** @return*/Integer getUserCount(QueryUserReq queryUserReq);

 6.UserMapper.xml(新增两个sql)

    <select id="getUserList" resultMap="BaseResultMap" parameterType="org.wal.userdemo.DTO.req.QueryUserReq">select * from user<where><if test="name != null and name != ''">and name like concat('%',#{name},'%')</if><if test="birthday != null">and birthday = #{birthday}</if>and del_flag = 0</where>limit #{page},#{limit};</select><select id="getUserCount" resultType="Integer" parameterType="org.wal.userdemo.DTO.req.QueryUserReq">select count(*) from user<where><if test="name != null and name != ''">and name like concat('%',#{name},'%')</if><if test="birthday != null">and birthday = #{birthday}</if>and del_flag = 0</where>;</select>

4.新增工具类

1.新增工具类BeanUtils.java,具体体现在MenuServiceImpl.java类中copy菜单树,如下:

    /*** 获取用户菜单列表* @param userId* @return*/@Overridepublic List<TreeDataResp> getMenuList(String userId) {List<MenuEntity> menuList = menuMapper.getMenuList(userId);List<TreeDataResp> treeDataRespList =BeanUtils.copyAsList(menuList, TreeDataResp.class);return buildMenuTree(treeDataRespList);}
(为什么不直接用MenuEntity.java来构建树结构?,为了确保entity无属性、字段、方法侵入,解耦entity,声明resp类更容易理解和维护)。

此工具类是对org.springframework.beans.BeanUtils的封装。有需要的同学可以去一下链接查找:

 gitee地址dev-utils分支,此分支是我用来实现和调试、测试工具类的分支。

5.新增菜单树返回类


import lombok.Data;import java.util.List;
@Data
public class TreeDataResp {/*** 主键*/private Integer id;/*** 菜单名称*/private String menuName;/*** 父菜单ID*/private Integer parentId;/*** 路由路径*/private String path;/*** 组件路径*/private String component;/*** 权限标识*/private String perms;/*** 图标*/private String icon;/*** 排序*/private Integer sort;/*** 是否显示(0隐藏,1显示)*/private Integer visible;/*** 子菜单*/private List<TreeDataResp> children;
}

6.配置类、拦截器 

1.新增JwtInterceptor.java拦截web请求,校验token信息。


import io.jsonwebtoken.JwtException;import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.wal.userdemo.utils.JwtUtil;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Slf4j
@Component
public class JwtInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token = request.getHeader("Authorization");if (token != null && token.startsWith("Bearer ")) {token = token.substring(7);try {String username = JwtUtil.parseUsername(token);// 可以将 username 存入 request 或 SecurityContextlog.info("用户 {} 使用正确的token访问了后端接口", username);return true;} catch (JwtException e) {response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "无效 Token");return false;}} else {response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "缺少 Token");return false;}}
}

2.新增WebConfig.java类,针对特定路由接口挂载JwtInterceptor拦截器,忽略登录接口。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.wal.userdemo.interceptor.JwtInterceptor;@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate JwtInterceptor jwtInterceptor;/*** 添加拦截器* 拦截路径为/api/**的请求,除了 /api/auth/login请求* @param registry*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(jwtInterceptor).addPathPatterns("/api/**").excludePathPatterns("/api/auth/login");}
}

至此,后端的调整暂时就这样。 

三、前端调整

1.请求调整

1.重写login.vue的js部分,抽离请求体,在src创建api目录,在api下创建login.js,在js部分引入

import { login } from '@/api/login';export default {name: 'UserLogin',data() {return {formData: {username: '',password: ''},rules: {username: [{ required: true, message: '用户名不能为空', trigger: 'blur' }],password: [{ required: true, message: '密码不能为空', trigger: 'blur' }],}};},methods: {async login() {try {const res = await login(this.formData);console.log('res.code', res)if (res.data.code === 200) {const token = res.data.data;localStorage.setItem('token', token);this.$router.push('/');this.$message.success('登录成功');} else {this.$message.error(res.data.message || '登录失败');}} catch (error) {this.$message.error('请求异常,请检查网络或服务端状态');}}}
};

2.login.js如下:

// src/api/login.jsimport request from '@/utils/request';/*** 用户登录* @param {Object} data - 登录参数,如用户名和密码* @returns {Promise}*/
export function login(data) {return request({url: '/auth/login',method: 'post',data,});
}/*** 用户退出(登出)* @returns {Promise}*/
export function logout() {return request({url: '/auth/logout',method: 'post',});
}

2.页面布局、样式调整

1.user.vue 

1.user.vue布局调整

<template><div><!-- 查询条件 --><el-form :inline="true" label-position="right" label-width="80px" :model="queryForm"class="demo-form-inline query-border-container"><el-row :gutter="20" justify="center"><!-- 姓名 --><el-col :span="7"><el-form-item label="姓名"><el-input v-model="queryForm.name" placeholder="请输入姓名"></el-input></el-form-item></el-col><!-- 出生日期 --><el-col :span="7"><el-form-item label="出生日期"><el-date-picker v-model="queryForm.birthday" type="date" placeholder="选择日期"style="width: 100%;"></el-date-picker></el-form-item></el-col><!-- 按钮组 --><el-col :span="7"><el-form-item><div style="display: flex; gap: 10px;"><el-button type="primary" @click="onQuery">查询</el-button><el-button @click="onReset">重置</el-button></div></el-form-item></el-col></el-row></el-form><!-- 用户列表 --><el-table :data="tableData" style="width: 100%;" class="table-border-container" max-height="480"v-loading="loading"><el-table-column type="index" label="序号" width="100" align="center"></el-table-column><el-table-column prop="name" label="姓名" width="180" align="center"></el-table-column><el-table-column prop="age" label="年龄" width="180" align="center"></el-table-column><el-table-column prop="birthday" label="出生日期" width="180" align="center"></el-table-column><el-table-column prop="birthday" label="出生日期" width="180" align="center"></el-table-column><el-table-column prop="birthday" label="出生日期" width="180" align="center"></el-table-column><el-table-column label="操作" width="180" align="center"><template #default="scope"><el-button type="primary" size="small" @click="handleEdit(scope.$index, scope.row)">编辑</el-button><el-button type="danger" size="small" @click="handleDelete(scope.$index, scope.row)">删除</el-button></template></el-table-column></el-table><el-pagination background layout="total,sizes,prev, pager, next" :total="total" @size-change="handleSizeChange":page-size.sync="queryForm.limit" :page-sizes="[10, 20, 50, 100]" class="page-border-container"></el-pagination></div></template><script>
import { getUserList } from '@/api/permission/user';export default {name: 'userView',data() {return {tableData: [],queryForm: {page: 1,limit: 10,username: '',birthday: '',},total: 0,loading: false,};},created() {this.getUserList();},methods: {getUserList() {this.loading = true;getUserList(this.queryForm).then(res => {if (res.data.code == 200) {this.tableData = res.data.data;this.total = res.data.total;// this.$message.success("获取用户列表成功!");} else {this.$message.error("获取用户列表失败!");}}).finally(() => {this.loading = false;});},// 查询onQuery() {this.getUserList();},// 重置表单并查询onReset() {this.queryForm = {page: 1,limit: 10,name: '',birthday: '',};this.getUserList();},handleSizeChange(val) {this.queryForm.limit = val;this.getUserList();},handleEdit(index, row) {console.log(index, row);this.$message.success('编辑成功');},handleDelete(index, row) {console.log(index, row);this.$message.success('删除成功');},},
};
</script>
<style scoped>
.query-border-container {border: 1px dashed #dcdcdc;border-radius: 8px;padding: 8px 16px;background-color: #fff;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);margin-bottom: 12px;
}.table-border-container {border: 1px dashed #dcdcdc;border-radius: 8px;padding: 8px 16px;background-color: #fff;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);margin-bottom: 12px;
}.page-border-container {border: 1px dashed #dcdcdc;border-radius: 8px;padding: 8px 16px 8px 16px;background-color: #fff;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);margin-bottom: 1px;
}.el-table .el-table__cell {padding: 5px 0px !important;
}.el-form-item {margin-bottom: 2px !important;
}
</style>

 2.同样的,js请求抽出来到user.js下,目录在src/api/permission/下,

import request from '@/utils/request';/*** 查询用户列表(分页)* @param {Object} params - 请求参数,如 page, limit 等*/
export function getUserList(params) {return request({url: '/user/getUserList',method: 'post',data : params,});
}

3. user.vue作为后续页面的参考页面,所以我把CSS部分抽出来到src/assets/css/global.css如下:

.query-border-container {border: 1px dashed #dcdcdc;border-radius: 8px;padding: 8px 16px;background-color: #fff;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);margin-bottom: 12px;
}.table-border-container {border: 1px dashed #dcdcdc;border-radius: 8px;padding: 8px 16px;background-color: #fff;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);margin-bottom: 12px;
}.page-border-container {border: 1px dashed #dcdcdc;border-radius: 8px;padding: 8px 16px 8px 16px;background-color: #fff;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);margin-bottom: 1px;
}.el-table .el-table__cell {padding: 5px 0px !important;
}.el-form-item {margin-bottom: 2px !important;
}

 CSS作为全局页面的样式需要在main.js中挂载,添加如下代码:

import '@/assets/css/global.css';
2.index.vue 

1.index.vue页面调整,主要是抽取js请求,调整布局和响应式菜单,如下:

<template><el-container class="home-container"><!-- 左侧区域 --><el-aside class="left-section" :width="'12%'"><!-- 左上部分:logo + 标题 --><div class="top-left"><div class="logo-container"><img src="../assets/logo.png" alt="logo"></div><h1>我的管理系统</h1></div><!-- 左下部分:菜单 --><el-menu default-active="1" class="sidebar-menu" :collapse="isCollapse" :collapse-transition="false"@open="handleOpen" @close="handleClose" background-color="#304156" text-color="#fff"active-text-color="#ffd04b"><el-submenu v-for="menu in menuList" :key="menu.id" :index="menu.id + ''"><template #title><i :class="'el-icon-' + menu.icon"></i><span>{{ menu.menuName }}</span></template><el-menu-item v-for="child in menu.children" :key="child.id" :index="child.path"@click="handleMenuClick(child)">{{ child.menuName }}</el-menu-item></el-submenu></el-menu></el-aside><!-- 右侧区域 --><el-container class="right-section"><!-- 右上部分:顶部导航 --><el-header class="top-right-header"><div class="header-right"><span>欢迎,Admin</span><el-button type="text" @click="logout">退出</el-button></div></el-header><!-- 右下部分:主内容区域 --><el-main class="main-content"><router-view /><user /></el-main></el-container></el-container>
</template><script>
import user from './user.vue'
import { logout } from '@/api/login'
import { getMenuList } from '@/api/permission/menu'export default {name: 'userIndex',components: { user },data() {return {isCollapse: false, // 默认展开menuList: [],// 菜单列表};},created() {this.getMenuList();},methods: {getMenuList() {getMenuList().then(res => {console.log('res.data', res.data)if (res.data.code === 200) {this.menuList = res.data.data || [];this.$message.success("获菜单列表c成功!");} else {this.$message.error("获菜单列表失败!");}});},logout() {logout().then(res => {if (res.code === 200) {localStorage.removeItem('token');this.$router.push('/login');this.$message.success('退出成功');} else {this.$message.error('退出失败');}}).catch(() => {this.$message.error('请求异常');});},handleMenuClick(menuItem) {this.$router.push(menuItem.path); // 跳转到对应路径},handleOpen(key, keyPath) {console.log(key, keyPath);},handleClose(key, keyPath) {console.log(key, keyPath);},},
};
</script><style scoped>
.home-container {height: 100vh;
}/* 左侧整体样式 */
.left-section {display: flex;flex-direction: column;background-color: #304156;color: white;padding: 10px;width: 50px;
}/* 左上角 logo 和标题 */
.top-left {display: flex;align-items: center;margin-bottom: 20px;
}.logo-container {margin-right: 10px;margin-top: 5px;
}.logo-container img {height: 20px;width: auto;object-fit: contain;
}.top-left h1 {font-size: 18px;margin: 0;color: white;
}/* 菜单样式 */
.sidebar-menu {flex: 1;border-right: none;
}/* 右侧整体样式 */
.right-section {display: flex;flex-direction: column;
}/* 右上角导航栏 */
.top-right-header {display: flex;justify-content: flex-end;align-items: center;background-color: #ffffff;box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);padding: 0 20px;
}.header-right {display: flex;align-items: center;
}/* 主内容区域 */
.main-content {padding: 20px;
}
</style>

2.index.vue抽取的js在src/api/permission/下,menu.js如下:

import request from '@/utils/request';
/*** 查询菜单列表* @param {Object} userId {可选} - 用户ID
}*/
export function getMenuList() {return request({url: '/menu/getMenuList',method: 'get',});
}

3.请求拦截

1.在src下新建utils目录,在utils下新建request.js,所以请求js都要导入request.js,在request.js中声明请求配置、请求拦截器,如下:

import axios from 'axios';const service = axios.create({baseURL: process.env.VUE_APP_BASE_API || '/api', // 使用环境变量或默认值timeout: 5000,
});// 请求拦截器:添加 token 到 header
service.interceptors.request.use(config => {const token = localStorage.getItem('token');if (token) {config.headers['Authorization'] = 'Bearer ' + token;}return config;},error => {return Promise.reject(error);}
);
export default service;

至此,前端布局、请求调整到此结束。 

四、开发过程中的问题

1.code review

在调试过程中,不断的重启后端项目,导致token失效,请求都是401未授权访问。

解决方案:在request.js中定义响应拦截器,把遇到error = 401重新跳转到登录页。

//响应拦截器(可选启用)
service.interceptors.response.use(response => {return response;},error => {if(error.response.data.error == 'Unauthorized'){console.error('token已失效请重新登录');localStorage.removeItem('token');window.location.href = '/login';}console.error('网络异常:', error);return Promise.reject(error.message);}
);

五、附:源码

1.源码下载地址

https://gitee.com/wangaolin/user-demo.git

同学们有需要可以自行下载查看,此文章是dev-vue分支。

六、结语

此次开发+调整只是为了后续开发有个参照,下一篇文章具体开发首页和权限管理,有需要的同学可以关注我。

(注:接定制化开发前后端分离项目,私我)


文章转载自:

http://uJE0AMmI.pgfkL.cn
http://hczusGYG.pgfkL.cn
http://Yt2mhl2j.pgfkL.cn
http://GoZihf9o.pgfkL.cn
http://H6d7L175.pgfkL.cn
http://rRriNQx2.pgfkL.cn
http://leFAeppP.pgfkL.cn
http://zH8wGXg0.pgfkL.cn
http://uokXFH3B.pgfkL.cn
http://aQu9NshN.pgfkL.cn
http://plhiNZer.pgfkL.cn
http://5RgtozKB.pgfkL.cn
http://NiEq7GtA.pgfkL.cn
http://qM8LLfoz.pgfkL.cn
http://YRa7s3ry.pgfkL.cn
http://pPKDBYrs.pgfkL.cn
http://mf1Qctbx.pgfkL.cn
http://DOKudXN9.pgfkL.cn
http://f09jCNu6.pgfkL.cn
http://esXatQnP.pgfkL.cn
http://A8KrDLdz.pgfkL.cn
http://gK853t5O.pgfkL.cn
http://OT0v2dyT.pgfkL.cn
http://nIOg9NUR.pgfkL.cn
http://8H2eecpC.pgfkL.cn
http://TThYvszA.pgfkL.cn
http://PbgMo5cK.pgfkL.cn
http://Cz9lv4sQ.pgfkL.cn
http://RvGV4qAX.pgfkL.cn
http://FE3IfwKU.pgfkL.cn
http://www.dtcms.com/wzjs/610390.html

相关文章:

  • 哪个网站做黄金交易最好wordpress get cat
  • 二级网站内容建设要求北京外贸网站制作公司
  • 乐清网络网站建设青海高端网站建设价格
  • 找网站做任务qq红包wordpress页面后缀.html和
  • 网站淘宝客一般怎么做手机装修设计软件app
  • 确定网站文案简单asp网站源码
  • 在哪个网站做视频可以赚钱网站发布与推广方式
  • 事业单位网站方案wordpress即时聊天插件
  • 成都网站开发公司绍兴柯桥哪里有做网站的
  • 商业网站建设与运营运行下打开wordpress
  • 网站架设建设wdcp更改网站域名
  • 做基因结构可以用哪个网站茌平网站制作
  • 百度做网站 推广费用怎么收河北邯郸中考成绩公布时间
  • 杭州网络科技网站建设wordpress myisam
  • 福州外贸网站建设工厂的网站在哪里做的
  • 做网站需要什么资质做网站 广州
  • 网站维护的内容和步骤百度云网盘免费资源
  • 北京市住房及城乡建设部网站企业网站建设的重要性
  • 易语言可以做网站了吗汕头个人网站推广建设
  • 南宁做网站方案品牌营销专家
  • 信息发布型网站是企业网站的什么推广链接代点
  • 天津 交友 网站建设企业网站建设视频
  • 毕业设计网站开发杭州 平台 公司 网站建设
  • 医院网站主页面设计地方门户网站域名
  • 甜蜜高端定制网站wordpress主题 四亩地
  • 网站建设相关新闻学校校园网站建设服务
  • 网站建设工作稳定吗ui设计师面试问题及答案
  • 档案网站建设的步骤网站如何做美工
  • wordpress语言切换网站个体营业执照可以做网站嘛
  • 武进网站建设价位怎么查看网站是否被百度收录