vue,vuex的后台管理项目架子structure-admin,后端服务nodejs,前端vue页面

之前写过一篇vue初始化项目,构建vuex的后台管理项目架子,这个structure-admin-web所拥有的功能

1、vuex来实现状态管理

2、静态页面,未引入后端服务

3、组件是用的是element-ui

4、页面布局是上左右,左右布局使用的弹性和布局flex,左边定宽,右边计算宽度

5、左右的滚动条是相互独立的,去掉body上的滚动条

6、没有业务代码,仅仅是一个静态的vuex的架子

说明:之前使用左侧menu的fixed布局,发现element-ui的弹窗组件不能正常显示,考虑换成flex布局

接下来,针对structure-admin-web的不足,进行了补充,开发了具有登陆的structure-admin项目,技术站:主要是node+vue+redis+mysql+es6

欢迎访问https://github.com/saucxs/structure-admin

接下来:

一、后端服务nodejs,thinjs的redis配置,操作数据库

二、前端vue+vuex全局路由守卫,axios请求拦截

三、项目启动必读

一、后端服务nodejs,thinjs的redis配置,操作数据库

我使用的是thinkjs,一个nodejs的框架。

1、首先介绍登陆的控制

逻辑:

(1)已经登陆的,直接根据的路由跳到相应页面;

(2)已经登陆的,不能跳到登陆页面,跳到首页;

(3)没有登陆的,输入url必须跳到登陆页;

(4)退出系统的,必须回到登陆页,状态是未登录

1.1 thinkjs的redis的配置文件adapter.js

exports.session = {
    type: ‘redis‘,
    common: {
        cookie: {
            name: ‘thinkjs‘,
            keys: [‘werwer‘, ‘werwer‘],
            signed: true
        }
    },
    redis: {
        handle: redisSession,
        host: ‘127.0.0.1‘,
        port: 6379,
        password: ‘a123456‘
    }
};

设置的由redis的服务地址host,端口,以及redis的密码,redis的搭建和配置,参考安装window下的redis,redis可视化管理工具(Redis Desktop Manager)安装,基础使用,实例化项目这篇文章。

1.2  在每一次前端请求的路由的时候,都会去redis服务器中去取userInfo的信息

如果为空,返回前端data为空,前端在路由过滤中,跳到登陆页,如果有值就正常返回。

async __before() {
        let user = await this.session("userInfo");
        if(user) {
            this.user = user;
        } else {
            this.user = ‘‘;
        }
    }

这个在nodejs的控制器controller里,在每一次前端的请求发送到后端的时候,都会去redis的取userInfo的值,

let user = await this.session("userInfo");

这个userInfo的值也是自己在登陆的时候,把登陆成功之后的个人信息加入到redis服务中

1.3 在登陆成功的时候讲个人信息加到redis服务中

async loginAction() {
        let {username, password} = this.post();try {
            let user = await this.model(‘user‘).where({
                username,
            }).find();
            if(user.password && user.password == password) {
                // login success
                await this.session(‘userInfo‘,{username, userId:user.id});
                return this.success("登陆成功");
            } else {
                return this.fail("用户名或密码错误")
            }
        }
        catch(e) {
            console.log(e);
            return this.fail("登录失败")
        }

这个就是将个人信息加入到redis中

await this.session(‘userInfo‘,{username, userId:user.id});

WEB 请求中经常通过 session 来维持会话的,框架通过 think-session 和 Adapter 来支持 session 功能。

2、介绍登出(退出)的控制

 async logoutAction() {
        try {
            await this.session(null);
            return this.success("登出成功");
        } catch(e) {
            return this.fail(`登出失败${e}`)
        }
    }

这个就是前端发的请求登出,直接将redis的置空,根据前端路由跳转到登陆页,这时候redis的服务中没有值,就不会跳转到其他页面

3、数据库的配置adapter.js

exports.model = {
  type: ‘mysql‘,
  common: {
    logConnect: true,
    logSql: true,
    logger: msg => think.logger.info(msg)
  },
  mysql: {
    handle: mysql,
    database: ‘example‘,
    prefix: ‘example_‘,
    encoding: ‘utf8‘,
    host: ‘127.0.0.1‘,
    port: ‘3306‘,
    user: ‘root‘,
    password: ‘123456‘,
    dateStrings: true
  }
};

common部分是配置是否将sql的语句的操作日志打出来,这样便于我们在开发的时候的调试和修改bug

4、操作数据库

项目开发中,经常需要操作数据库(如:增删改查等功能),手工拼写 SQL 语句非常麻烦,同时还要注意 SQL 注入等安全问题。为此框架提供了模型功能,方便操作数据库。

Mysql 的 Adapter 为 think-model-mysql,底层基于 mysql 库实现,使用连接池的方式连接数据库,默认连接数为 1。

登陆的接口来说明:this.model说明使用封装好的model,find是查找单条数据,在user的这张表中查找username值为前端传来的username的值,返回的值赋给user中。

async loginAction() {
        let {username, password} = this.post();
        try {
            let user = await this.model(‘user‘).where({
                username,
            }).find();
            if(user.password && user.password == password) {
                // login success
                await this.session(‘userInfo‘,{username, userId:user.id});
                return this.success("登陆成功");
            } else {
                return this.fail("用户名或密码错误")
            }
        }
        catch(e) {
            console.log(e);
            return this.fail("登录失败")
        }

think.Model 基类提供了丰富的方法进行 CRUD 操作,下面来一一介绍。

查询数据

模型提供了多种方法来查询数据,如:

  • find 查询单条数据
  • select 查询多条数据
  • count 查询总条数
  • countSelect 分页查询数据
  • max 查询字段的最大值
  • avg 查询字段的平均值
  • min 查询字段的最小值
  • sum 对字段值进行求和
  • getField 查询指定字段的值

同时模型支持通过下面的方法指定 SQL 语句中的特定条件,如:

  • where 指定 SQL 语句中的 where 条件
  • limit / page 指定 SQL 语句中的 limit
  • field / fieldReverse 指定 SQL 语句中的 field
  • order 指定 SQL 语句中的 order
  • group 指定 SQL 语句中的 group
  • join 指定 SQL 语句中的 join
  • union 指定 SQL 语句中的 union
  • having 指定 SQL 语句中的 having
  • cache 设置查询缓存

添加数据

模型提供了下列的方法来添加数据:

  • add 添加单条数据
  • thenAdd where 条件不存在时添加
  • addMany 添加多条数据
  • selectAdd 添加子查询的结果数据

更新数据

模型提供了下列的方法来更新数据:

删除数据

模型提供了下列的方法来删除数据:

用项目的代码举栗子:

(1)查询单条数据,用find(),条件为:工号(usernum)为180909,用户名(username)为saucxs ,并且填写时间(time)为这周的时间范围的时间戳,返回的是对象object

 let weekly = await this.model(‘week‘).where({
     usernum: ‘180909‘,    username: ‘saucxs‘,    time: {‘>‘: startWeekStamp, ‘<‘: endWeekStamp}
 }).find();

解读:model(‘week‘)的意思,取得是week的数据表

(2)查询多条数据,用select(),条件:公司id(company_id)为data的数据,返回的是数组array

let department = await this.model(‘department‘).where({company_id: ‘data‘}).select();

(3)查询表中的具体的列数据,用field()

departmentMemberList = await this.model(‘user‘).field(‘id, company_id, company_name, department_id, department_name, email, role, role_name, username, usernum,telephone‘).where({
          company_id: this.user.company_id,
          role: {‘>=‘: this.user.role}
        }).find();

解读:this.user.company_id取的是登陆用户的公司id,{‘>=‘: this.user.role}为比登陆用户的角色

(4)分页查询,用page(page, pagesize)和countSelect(),返回的数据是对象

departmentMemberList = await this.model(‘user‘).field(‘id, company_id, company_name, department_id, department_name, email, role, role_name, username, usernum,telephone‘).where({
          company_id: this.user.company_id,
          role: {‘>=‘: this.user.role}
        }).order("department_id asc , role asc").page(page, pagesize).countSelect();

解读:返回的对象,如下图所示:(count是总条数,currentPage为当前页,data是数据的数组,pageSize为每一页展示几条,totalPages为总共有多少页)

(5)排序,倒序(desc)和正序(asc),用order("参数1 asc,参数2 desc”)

departmentMemberList = await this.model(‘user‘).field(‘id, company_id, company_name, department_id, department_name, email, role, role_name, username, usernum,telephone‘).where({
          company_id: this.user.company_id,
          role: {‘>=‘: this.user.role}
        }).order("department_id asc , role asc").page(page, pagesize).countSelect();

(6)删除,用delete(),条件用where

 await this.model(‘department‘).where({company_id, department_id}).delete();

(7)新增,用add(),没有where

  await this.model(‘department‘).add({
          company_id: this.user.company_id, company_name: this.user.company_name, department_id, department_name
        });

(8)改,用update(),条件where

 await this.model(‘user‘).where({id}).update({
                usernum, username, telephone, role, role_name,email, company_id, company_name, department_id, department_name
              });

手动执行 SQL 语句

有时候模型包装的方法不能满足所有的情况,这时候需要手工指定 SQL 语句,可以通过下面的方法进行:

  • query 手写 SQL 语句查询
  • execute 手写 SQL 语句执行

具体的可以参考thinkJS的官方文档的数据操作这块:https://thinkjs.org/zh-cn/doc/3.0/relation_model.html

二、前端vue+vuex全局路由守卫,axios请求拦截

刚才简单的说了一下nodejs的后端启动的服务,封装的接口,而前端调用这个接口使用的是url是:模块名/控制器名/方法名,这个可以在配置文件中修改定义的方法

1、全局路由守卫

全局路由守卫是每一次都会判断是否登陆(也就是判断redis服务中是否有值)。已经登陆(后端返回的用户权限信息),则判断当前要跳转的路由,用户是否有权限访问,可以考虑在用户登陆之后将用户权限把路由过滤一遍生成菜单,菜单保存到vuex中。

/*路由处理*/
router.beforeEach((to, from, next) => {
  let menuId;
  let auditResult;
  let applicationVerifyFlag;
  let key = to.meta.key;
  if (key) {
    store.dispatch("getUserInfo", {}).then(response => {if(!response.data){
        if (to.path !== ‘/login‘) {
          return next(‘/login‘);
        }
        next();
      }else{
        if (to.path == ‘/login‘) {
          return next(‘/writeWeekly‘);
        }
        store.commit("USER_INFO", response.data);
        next();
      }
    });
  } else {
   next();
  }
});

根据这个key来判断是否有权限,取得是路由中meta的key的值。

  routes: [
    {
      path: ‘/login‘,
      name: ‘login‘,
      meta: {
        key: ‘0‘
      },
      component: login
    },
    {
      path: ‘/‘,
      name: ‘home‘,
      component: home,
      children: [{
        path: ‘/writeWeekly‘,
        name: ‘writeWeekly‘,
        meta: {
          key: ‘1‘
        },
        component: writeWeekly
      }]
    }
  ]

2、axios请求拦截

统一处理所有的http请求和响应的,通过配置http request interceptors为http头部增加Authorization字段,其内容为Token,通过配置http response interceptors,当后端接口返回401 Unauthorized(未授权),让用户重新登录。

// 开发环境调试用户信息
axios.interceptors.request.use(config => {
    if (process.env.NODE_ENV === ‘development‘) {
      config.headers["username"] = "189090909";
    }
    return config;
});

axios.interceptors.response.use(
  response => {
    let data = response.data;
    console.log(data, ‘data‘);
    if (!data.data) {
      //   登陆成功的回调地址
      return data;
    } else {
      return data;
    }
  },
  error => ({
    code: -1,
    msg: "网络异常"
  })
);

对所有的请求进行了封装。

// get请求配置
let getConfig = {
    url: ‘‘,
    baseURL: serveUrl,
    headers: {
    ‘X-Requested-With‘: ‘XMLHttpRequest‘
  },
  paramsSerializer(params) {
    return Qs.stringify(params, {
      arrayFormat: ‘brackets‘
    })
  },
  timeout: 5000
}

// post请求配置
let postConfig = {
    url: ‘‘,
    baseURL: serveUrl,
    headers: {
      ‘Content-Type‘: ‘application/json‘,
      ‘X-Requested-With‘: ‘XMLHttpRequest‘
    },
    transformRequest: [function (data) {
      return JSON.stringify(data.params || {})
    }],
    timeout: 5000
}

export {
    serveUrl,
    getConfig,
    postConfig,
  }

三、项目启动必读

1、首先你的环境是nodejs,不会安装配置参考:http://www.mwcxs.top/page/440.html

2、clone下来项目

git clone https://github.com/saucxs/structure-admin.git

3、分别针对前端vuestructure-admin-web的文件夹和node后端structure-admin-node,安装相应依赖

npm install

4、安装redis(可以考虑安装RedisDesktopManager)

参考:安装window下的redis,redis可视化管理工具(Redis Desktop Manager)安装,基础使用,实例化项目

5、安装mysql,这个就不赘述

6、修改nodejs的后端的配置文件adapter.js,config.js这两个文件中

adapter.js

exports.cache = {
    type: ‘redis‘,
    common: {
        timeout: 24 * 60 * 60 * 1000 // millisecond
    },
    redis: {
        handle: redisCache,
        host: ‘127.0.0.1‘,
        port: 6379,
        password: ‘a123456‘  //redis安装时候设置的秘密
    }
};////
exports.model = {  type: ‘mysql‘,  common: {    logConnect: true,    logSql: true,    logger: msg => think.logger.info(msg)  },  mysql: {    handle: mysql,    database: ‘weekly‘,    prefix: ‘week_‘,    encoding: ‘utf8‘,    host: ‘127.0.0.1‘,   //本地数据库    port: ‘3306‘,     //数据库端口    user: ‘root‘,    //数据库的用户名    password: ‘123456‘,    //数据库该用户名的密码    dateStrings: true  }};

7、分别对前后端分离的项目启动

(1)前端vuestructure-admin-web的启动

npm run dev

(2)和node后端structure-admin-node的启动

npm start

8、这样就可以启动

(1)登陆页

(2)写周报页面

9、欢迎fork和start该项目

https://github.com/saucxs/structure-admin

不懂的地方可以提issue,欢迎提出来共同探讨

10、该项目架子搭的周报企业管理系统

在PC端,欢迎访问:http://120.27.109.67:8089/#/departmentManage,这个账号和密码,给出一个测试的,账号:test,密码:123456

原文地址:https://www.cnblogs.com/chengxs/p/9465482.html

时间: 2024-12-12 19:59:15

vue,vuex的后台管理项目架子structure-admin,后端服务nodejs,前端vue页面的相关文章

Vue电商后台管理系统项目第6篇-商品管理的商品列表和商品添加组件实现

开胃小菜—左侧导航菜单的动态生成 通过为指定的用户指定角色,那么这个用户登陆之后应该只能看到这个角色所对应的权限菜单, 我们是根据当前登陆用户去获取对应的菜单权限 步骤 分析接口文档 ,发现不用传递参数,因为它是根据当前登陆用户的token来动态获取当前用户的权限 添加接口方法获取动态的菜单数据 // 获取左侧菜单权限 export const getLeftMenu = () => { return axios({ url: `menus` }) } 实现菜单项的动态加载 获取数据之后,注意看

docloud后台管理项目(开篇)

最近朋友做app需要web做后台管理,所以花了一周时间做了这个项目. 废话不多说,开发环境是nginx+php5.3,使用thinkphp框架.是一个医疗器械数据统计的后台,业务功能很简单就是查看用户从app上面发布的数据. 由于刚接触thinkphp和一些前端的插件,所以遇到了很多问题,具体请看后续章节. 主要页面截图:

Vue电商后台管理系统项目第3篇-首页用户列表增删改查功能

前言 由于之前的作者没有再更新这个后台管理系统项目的文章了,我想着把它的项目重头到位做一遍,把剩下的文章写完,把这个项目记录完整,以后遇到类似的后台管理系统项目,可以快速复习一些知识点. 新的项目地址:https://github.com/C4az6/vue_manage_system 添加用户 这个操作在用户列表页面,所以路由不用再进行 处理了. 基于单文件组件: 添加事件绑定--弹出新增用户对话框 添加dialog对话框 Element-UI组件>dialog对话框>自定义内容>表单

zencart后台管理中选项名称和选项内容和属性控制页面出错解决办法 WARNING: An Error occurred, please refresh the page and try again

后台管理中选项名称和选项内容和属性控制出现以下错误的解决办法WARNING: An Error occurred, please refresh the page and try again zen cart v1.5.1 的一个bug,重新下载更新的zencart安装包,然后取出以下三个文件替换:admin/attributes_controller.phpadmin/option_names_manager.phpadmin/option_values_manager.php 或者手工修复如

Vue电商后台管理系统项目第4篇-权限管理页面实现

优化之前的分配角色功能 实现下拉列表的选项默认选中 为下拉列表的v-model赋值一个id,这个id会对应着下拉列表的value,如果赋值了Value,那么就会让这个value数据所对应的字符串数据显示 我们得先获取到这个用户的rid // 分配角色提交 grantrolesubmit () { if (this.grantForm.rid) { grantUserRole(this.grantForm.id, this.grantForm.rid) .then(res => { if (res

Vue电商后台管理系统项目第5篇-角色列表的增删改查&amp;&amp;角色授权

角色列表的增删改查 1.添加角色 先根据API文档编写接口: // 添加角色 export const addRolesApi = (data) => { return axios({ method: 'post', url: 'roles', data }) } 在角色组件内引用,然后给 添加角色 按钮绑定一个点击事件addRolesClick: <!-- 添加角色 --> <el-button type="success" plain @click=&quo

docloud后台管理项目(前端篇)

以下内容与主题无关,如果不想看可以直接忽视 !--忽视开始--! 给大家推荐一款强大的编辑器,那就是集响应快.体验好.逼格高.功能丰富为一体的sublime text 3.它除了以上特点,还有一个最重要的功能:方便快捷的插件扩展,支持大量插件而且均支持命令行安装,只要一条简单的命令就可以完成插件的安装.想要提高开发效率,sublime是一个很好的选择! !--忽视结束--! 以下为项目开发时遇到的问题或者学习到的前端技术: 1.height:100%设置无效 解决方法:html,body{mar

vue+elementui搭建后台管理界面

1 会话存储 使用html5的 sessionStorage 对象临时保存会话 // 保存会话 sessionStorage.setItem('user', username) // 删除会话 sessionStorage.removeItem('user', username) 2 将所有未登录会话重定向到 /login 用 vue-router 的 beforeEach 实现beforeEach 方法接收三个参数: to: Route: 即将要进入的目标 路由对象 from: Route:

vue+elementui搭建后台管理界面(3侧边栏菜单)

上一节搭好了主框架,但是标签页和侧边栏只是分别展示了各自的菜单,如何将二者联动起来? 定义路由规则:当有 children 属性时,从 children 里取出 path 填充到侧边栏,如: { path: '/', redirect: '/dashboard', name: 'Container', component: Container, children: [ {path: 'dashboard', name: '首页', component: Dashboard, }, {path: