实现全栈收银系统(Node+Vue)(下)

2,603 阅读2分钟

基于上一篇中的开发基本上实现了登录注册,通过token拿数据等一些登录涉及到的功能开发,基本上后端的功能已全部完成,可以看下上一篇实现全栈收银系统(Node+Vue)(上)的分享。 今天我们需要进行实现的功能包前端页面的编写和开发

先看效果

前端项目创建

创建在node-app项目(即在node项目里面) vue create client

前后端连载

安装命令 npm install concurrently

将Vue项目执行运行的命令添加 "start": "npm run serve"

在node项目中配置成,我们只需要执行 npm run dev就能让后台跟前台都运行起来

功能开发模块

设置全局的404页面

在路由页面中

  {
    path: '*',
    name: '/404',
    component: NotFound
  },

注册(数据axios拦截,config配置)

请求拦截

axios.interceptors.request.use(config => {
    return config;
},error => {
    return Promise.reject(error);
})

响应拦截

axios.interceptors.response.use(response => {
    return response;
}, error => {
    Message.error(erroe.response.data);
    return Promise.reject(error);
})

记得 export default axios

main.js中配置 Vue.prototype.$axios = axios;

登录(token设置,vuex状态存储,)

  1. 解析token的值 npm install jet-decode jwt_decode(token)
  2. 数据储存到localStorage中,在放到vuex中进行存储,目的是后期判断token是否有效等操作,其次vue插件能够通过定义的type进行监控到数据获取变化
    vuex操作
const type = {
  SET_AUTHENTICATION: "SET_AUTHENTICATION", //判断是否认证通过 (自定义的type名称)
  SET_USER: 'SET_USER',
}
const mutations ={
  [type.SET_AUTHENTICATION](state,isAuthentication) {
    if(isAuthentication) state.isAuthentication = isAuthentication;
    else state.isAuthentication = false;
  },

  [type.SET_USER](state,user) {
    if(user) state.user = user;
    else state.user = {};
  },
}
const actions = { //异步操作
  setAuthentication: ({commit},isAuthentication) => {
    commit(type.SET_AUTHENTICATION,isAuthentication);
  },
  setUser:({commit},user) => {
    commit(type.SET_USER,user);
  },
}

登录操作

// 解析token
const decode = jwt_decode(token);
// 存储数据
this.$store.dispatch("setAuthentication", !this.isEmpty(decode));
this.$store.dispatch("setUser", decode);
  1. 刷新的过程中根组件没有进行判断会使vuex的数据丢失,那么我们需要再App.vue中再次对token值获取

顶部实现(个人信息,退出)

个人信息

获取相应的头像,名字,等级我们可以在登录的时候通过解析tonken获取到的信息赋值,由于我们登录的时候将解析的tonken存入vuex中,故我们可以进行取值

token信息

获取tonken信息

 <span>{{user.name}}</span>
computed: {
    user() {
      return this.$store.getters.user;
    }
 }

退出

操作跟我们token过期操作雷同,需要清除相应的token数据,将状态更改为false ,故我们可以通过vuex中为退出设置个方法调用即可

//vuex
const actions = { 
  //退出登录清除状态
  clearCurrentState:({commit}) => {
    commit(type.SET_AUTHENTICATION,false);
    commit(type.SET_USER,null)
  }
}
// HeadNav
logout() {
    localStorage.removeItem('eleToken');
    //设置vuex store
    this.$store.dispatch('clearCurrentState');
    //跳转
    this.$router.push('/login');
}

资金管理(父子传值,添加,编辑,删除,筛选,分页)

界面设置

参考element中的table自定义列模板 ,此处的数据遍历按照文档中的走相应的更改字段即可

添加和编辑

此处实现是雷同的,共用同个弹窗组件,其中涉及到父子组件之间的相互传值。 新建出dialog自定义内容,此处技术点

// 由父组件的数据传入进行接收
props: {
    dialog: Object,
    form: Object
},
// 提交表单以后将数据传回去给父组件 (此处的提交写法是表单额提交写法)
onSubmit(form) {
  this.$refs[form].validate(valid => {
    if (valid) {
      //表单数据验证完成之后,提交数据;
      const url =
        this.dialog.option == "add" ? "add" : `edit/${this.form.id}`;
        this.$axios.post(`/api/profile/${url}`, this.form).then(res => {
        // 操作成功
        this.dialog.show = true;
        this.$emit("update"); 
      });
    }
  });
}

添加的时候,我们通过点击父页面改变自定义的数组数据,让子组件显示,通过提交数据传回给父组件,update刷新父组件当前列表重新请求,继而关闭弹窗。

在此处中我们对不同操作相应的data数据都要做处理,编辑的时候,我们对from中的数据进行赋值操作,添加的时候清空数据

<!-- 弹框页面 -->
<DialogFound :dialog='dialog' :form='form' @update="getProfile"></DialogFound>
data() {
    //这些数据是自定义的数据,包括表单信息,控制子组件的数组数据
    dialog: {
        show: false,
        title: "",
        option: "edit"
      },
      form: {
        type: "",
        describe: "",
        income: "",
        expend: "",
        cash: "",
        remark: "",
        id: ""
      },
},
methods: {
//刷新数据
    getProfile() {
      // 获取表格数据
      this.$axios("/api/profile").then(res => {
        // this.tableData = res.data;
        this.allTableData = res.data;
        this.filterTableData = res.data;
        // 设置分页数据
        this.setPaginations();
      });
    },
}

删除

element自带了方法,我们只需要获取拿了进行使用就行了

onDeleteMoney(row, index) {
  // 删除
  this.$axios.delete(`/api/profile/delete/${row._id}`).then(res => {
      console.log(JSON.stringify(res));
    this.$message("删除成功");
    this.getProfile();
  });
},

分页

模板参考element的分页,根据分页我们需要自定义的数组数据进行收集赋值

 paginations: {
    page_index: 1, // 当前位于哪页
    total: 0, // 总数
    page_size: 5, // 1页显示多少条
    page_sizes: [5, 10, 15, 20], //每页显示多少条
    layout: "total, sizes, prev, pager, next, jumper" // 翻页属性
  },

我们需要再第一次数据加载的时候获取到全部的数组数据allTableData,设置一个空数组,将储存 过滤后的数组数据

setPaginations() {
  // 总页数
  this.paginations.total = this.allTableData.length; 
  this.paginations.page_index = 1;
  this.paginations.page_size = 5;
  // 设置默认分页数据
  //此处便将总的数据进行遍历,根据设置的初始值,将返回为true的数据储存在空数组中
  this.tableData = this.allTableData.filter((item, index) => {
    console.log(index < this.paginations.page_size);
    return index < this.paginations.page_size;
    //return index < page_size; 根据切换的页数进行过滤
    
  });
  console.log( this.tableData )
},

实现切换页数进行数据的改变

 handleCurrentChange(page) {
      // 当前页
      let sortnum = this.paginations.page_size * (page - 1);
      let table = this.allTableData.filter((item, index) => {
        return index >= sortnum;
      });
      // 设置默认分页数据
      this.tableData = table.filter((item, index) => {
        return index < this.paginations.page_size;
      });
      //第二种的实现
      // let tables = [];
      // for(let i=index;i<nums;i++) {
      //   if(this.allTableData[i]) {
      //     tables.push(this.allTableData[i]);
      //   }
      //   this.tableData = tables
      // }
    },

时间的筛选

时间的筛选中,我们需要重新定义一个新的全部数据的数组,通过获取两个时间段的时间格式后进行比较赋值到计算分页的数组当中,重新再执行分页的初始化函数

onScreeoutMoney() {
      // 筛选
      if (!this.search_data.startTime || !this.search_data.endTime) {
        this.$message({
          type: "warning",
          message: "请选择时间区间"
        });
        this.getProfile();
        return;
      }
      const stime = this.search_data.startTime.getTime(); //开始时间
      const etime = this.search_data.endTime.getTime(); //结束时间
      this.allTableData = this.filterTableData.filter(item => {
        let date = new Date(item.date);
        let time = date.getTime();
        return time >= stime && time <= etime;
      });
      // 分页数据
      this.setPaginations();
    }
  },

最终实现了vue+node实现的后台系统