本地数据库IndexedDB - 学员管理系统之列表管理(二)

 IndexedDB是浏览器提供的本地数据库,它可以被网页脚本创建和操作。IndexedDB允许存储大量数据,提供查找接口,还能建立索引。这些都是LocalStorage或Cookie不具备的。就数据库类型而言,IndexedDB不属于关系型数据库(不支持SQL查询语句),更接近NoSQL数据库。

        通过上一篇“本地数据库IndexedDB - 学员管理系统之登录(一)”,我们已完成了系统的登录功能,这一章节则完成相关列表管理功能,实现管理员列表、年级管理、班级管理、教师列表、学员列表等栏目的增删改查。

        由于这中间工作较忙,离下篇发布时间相隔较长,并且结合后期开发过程,对前期部分定义内容进行了修改,有些地方差异,大家可以重新翻看上一篇。

上篇地址:本地数据库IndexedDB - 学员管理系统之登录(一)_觉醒法师的博客-CSDN博客

        

一、管理员列表

        在开始前,我们将上一章节的用户登录信息再修复一下;当用户登录成功后,会将信息缓存到localStorage中,本地状态管理器中也会只在一份;用户列表管理时,遇到登录用户信息,需要判断是否可以修改或删除等,需要从store中获取用户信息,但是页面刷新后,store状态中的用户信息会丢失,这时我们在校验Token有效情况下,需要重新将缓存中的用户信息,保存到store状态中。打开store/actions.js文件,添加以下代码:

import Vue from 'vue'
import { USERINFO, TOKEN } from './mutationsType'
import { tokenIsFailure } from '@/api'

const actions = {
  /**
   * 重新加载缓存中用户信息
   */
  reloadUserInfo({commit}){
    let token = Vue.ls.get(TOKEN),
        userInfo = Vue.ls.get(USERINFO);
    if(token) {
      commit(TOKEN, token);
    }
    if(userInfo) {
      commit(USERINFO, userInfo);
    }
  },
   
  //...
}

1.1 获取用户列表

        首先我们在db/model/user.js中,定义loadUserAllList用户加载所有用户信息;筛选用户功能可通过传入name进行筛选,获取所有数据时通过filter进行过滤下即可;另外这里我们先使用getAll()方法来获取所有数据,在后期中我们会讲解如何进行分页查询。代码如下:

/**
 * 获取用户列表
 */
export const loadUserAllList = name => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName);
    //获取所有数据
    let alls = store.getAll();

    alls.onerror = function(e){
      reject(
        rJson(0, e, '查询出错了~')
      );
    }

    alls.onsuccess = function(e){
      let result = e.target.result;
      if(result){
        let data = result.map(item => {
              delete item['password'];
              delete item['accesstoken'];
              return item;
            });
        //如果name值存在,则进行过滤
        if(name){
          data = data.filter(item => item.name.includes(name));
        }
        resolve(
          rJson(1, data, '获取成功~')
        )
      }else{
        reject(
          rJson(0, null, '未查询到数据~')
        )
      }
      // console.log('store', result);
    }

  });
}

        第二步,在api/index.js中定义userAllList接口函数,代码如下:

import { loadUserAllList } from '@/db/model/user'


/**
 * 获取用户列表
 */
export const userAllList = keyword => {
  return loadUserAllList(keyword);
}

        html代码:

<template>
<div class="index-wrap">
  <el-breadcrumb separator-class="el-icon-arrow-right">
    <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
    <el-breadcrumb-item>管理员列表</el-breadcrumb-item>
  </el-breadcrumb>
  <br /><br />
  <!-- filter-wrap -->
  <div class="filter-wrap">
    <div class="item left">
      <el-form :inline="true" class="demo-form-inline">
        <el-form-item label="账号">
          <el-input size="small" v-model="keyword" placeholder="请输入账号"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button size="small" type="primary" @click="updateUserList">查询</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div class="item right">
      <el-form :inline="true" class="demo-form-inline">
        <el-form-item>
          <el-button size="small" type="primary" @click="addUserEvent">新增</el-button>
          <el-button size="small" type="danger" @click="deleteSelectedUser">删除</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
  <!-- /filter-wrap -->

  <!-- table-wrap -->
  <div class="table-wrap">
    <el-table
      :data="tableList"
      style="width: 100%">
      <el-table-column type="selection" label="选择" width="50" :selectable="selectableFunc"></el-table-column>
      <el-table-column prop="name" label="账号"></el-table-column>
      <el-table-column prop="phone" label="手机号"></el-table-column>
      <el-table-column prop="createtime" label="创建日期"></el-table-column>
      <el-table-column prop="updatetime" label="更新日期"></el-table-column>
      <el-table-column label="操作" width="150">
        <template slot-scope="scope">
          <el-button type="primary" size="mini" icon="el-icon-edit" circle></el-button>
          <el-button type="danger" size="mini" :disabled="userInfo.id==scope.row.id" icon="el-icon-delete" circle></el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
  <!-- /table-wrap -->
</div>
</template>

        样式部分:

.index-wrap{
  padding: 20px;
}

.filter-wrap{
  display: table;
  width: 100%;

  .item{
    display: table-cell;
    vertical-align: middle;

    &.left{
      text-align: left;
    }
    //left end
    &.right{
      text-align: right;
    }
    //right end
  }
}

        JS代码部分:

<script>
import { userAllList } from '@/api'
import { formatDate } from '@/utils/utils'
import { mapGetters } from 'vuex'

export default {
  data () {
    return {
      //选择ID
      selectId: 0,
      //查询关键字
      keyword: "",
      /**
       * 是否显示弹框
       */
      isShowDialog: false,
      /**
       * 列表数据
       */
      tableList: [],
      /**
       * 选的项
       */
      multipleSelection: []
    }
  },
  computed: {
    ...mapGetters(['userInfo'])
  },
  created() {
    this.updateUserList();
  },
  methods: {
    /**
     * 禁用当前登录用户的删除判断
     * @param {Object} row
     * @param {Object} index
     */
    selectableFunc(row, index){
      return row.id!=this.userInfo.id;
    },
    /**
     * 获取用户列表数据
     */
    updateUserList(){
      userAllList(this.keyword).then(res => {
        if(res.code==1&&Array.isArray(res['data'])){
          this.tableList = res.data.map(item => {
            item['createtime'] = formatDate(item.createtime);
            item['updatetime'] = formatDate(item.updatetime);
            return item;
          });
        }
        // console.log(res);
      }).catch(e => {
        this.tableList = [];
        console.log('e', e);
      });
      //ajax end
    }
  }
}
</script>

        以上准备工作做完后,我们页面就有用户数据了,如下图:

       大家可以观察到admin的多选项 和 删除 按钮都是禁用的,这里因为当前登录用户是无法删除自己的。如何实现的呢,删除按钮是通过store中取到的用户ID和列表渲染用户ID进行对比,判断为当前登录用户则禁用;多选功能则是通过selectable功能,与store中的用户ID进行对比来判断的。

        当然,现在列表数据是显示了,但是只有一条数据,无法通过条件进行筛选,这块等我们将新增功能完成后,再来操作。

1.2 新增数据

        首先,我们在db/model/user.js中定义toggleUser函数,用于新增 或 编辑用户信息;当数据为新增时,先判断用户名是否已存在,如已存在返回错误信息,不存在直接新增为新用户;当数据为编辑时,先获取该用户原始数据,用原始数据和新数据进行合并,如果使用put保存,会覆盖掉之前未修改数据。

        当编辑时候,先通过get()方法获取该用户所有信息,再合并数据。

        当新增时候,先通过name索引判断该用户是否存在,存在则返回提示信息;不存在则直接添加。

代码如下:

/**
 * 增加 或 编辑用户信息
 */
export const toggleUser = data => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store, index} = openTransactionIndex(storeName, 'name', CONST_READ.READWRITE);

    let res;
    //md5处理密码
    if(data['password']){
      data.password = hex_md5(data.password);
    }

    //用户ID存在,则为编辑
    if(data['id']&&data.id!=0){
      data['updatetime'] = new Date().getTime();

      //获取原数据
      res = store.get(data.id);

      res.onerror = function(e){
        reject(
          rJson(0, e, '查询出错了~')
        );
      }

      res.onsuccess = function(e){
        let result = e.target.result;
        if(result){
          //合并数据,并保存
          res = store.put(Object.assign(result, data));

          res.onerror = function(e){
            reject(
              rJson(0, e, '查询出错了~')
            );
          }

          res.onsuccess = function(){
            resolve(
              rJson(1, null, '保存成功~')
            )
          }
        }else{
          reject(
            rJson(0, e, '用户数据不存在~')
          );
        }
      }

    }
    //新增(需要判断用户名是否已存在)
    else{
      //通过索引 获取用户名,判断用户名是否已存在
      res = index.getKey(data.name);

      res.onerror = function(e){
        reject(
          rJson(0, e, '查询出错了~')
        );
      }

      res.onsuccess = function(e){
        let result = e.target.result;
        //如果用户名已存在,返回错误信息
        if(result){
          reject(
            rJson(0, e, '该用户名已存在~')
          );
        }
        //用户名不存在,则直接添加
        else{

          data['createtime'] = new Date().getTime();
          data['updatetime'] = new Date().getTime();
          res = store.add(data);

          res.onerror = function(e){
            reject(
              rJson(0, e, '查询出错了~')
            );
          }

          res.onsuccess = function(){
            resolve(
              rJson(1, null, '保存成功~')
            )
          }
        }
        //if 2 end
      }

      //索引 End
    }

    //if end

  });
}

       api/index.js添加addUserInfo()方法,代码如下:

import { toggleUser } from '@/db/model/user'

/**
 * 添加用户信息
 */
export const addUserInfo = param => {
  return toggleUser(param);
}

        接下来,我们来创建新增弹框组件,在components目录中创建UserDailog目录,再新增index.vue。

        弹框页面html代码部分:

<template>
  <el-dialog :title="uid!=0?'编辑':'新增'" :visible="visible" @close="closeEvent" width="420px" class="dialog-wrap">
    <el-form :model="form" :rules="rules"  status-icon ref="ruleForm">
      <el-form-item label="用户名" :label-width="formLabelWidth" prop="name">
        <el-input v-model="form.name" autocomplete="off" size="small"></el-input>
      </el-form-item>
      <el-form-item v-if="uid!=0" label="原密码" :label-width="formLabelWidth" prop="opwd">
        <el-input v-model="form.opwd" type="password" autocomplete="off" size="small"></el-input>
      </el-form-item>
      <el-form-item label="密码" :label-width="formLabelWidth" prop="password">
        <el-input v-model="form.password" type="password" autocomplete="off" size="small"></el-input>
      </el-form-item>
      <el-form-item v-if="uid==0||(uid!=0&&form.password)" label="确认密码" :label-width="formLabelWidth" prop="checkPass">
        <el-input v-model="form.checkPass" type="password" autocomplete="off" size="small"></el-input>
      </el-form-item>
      <el-form-item label="手机号" :label-width="formLabelWidth" prop="phone">
        <el-input v-model="form.phone" autocomplete="off" size="small"></el-input>
      </el-form-item>
    </el-form>
    <div slot="footer" class="dialog-footer">
      <el-button size="small" @click="closeEvent">取 消</el-button>
      <el-button size="small" type="primary" @click="submitForm">保 存</el-button>
    </div>
  </el-dialog>
</template>

        JS代码部分:

<script>
  import { getUserById, addUserInfo, editUserInfo } from '@/api'
  import { hex_md5 } from '@/utils/md5'
  export default {
    props: {
      //用户ID
      uid: {
        type: Number,
        default: () => 0
      },
      visible: {
        type: Boolean,
        default: () => false
      }
    },
    data(){
        var validateUsername = (rule, value, callback) => {
          if (value === '') {
            callback(new Error('请输入用户名'));
          } else {
            callback();
          }
        };
        var validatePhone = (rule, value, callback) => {
          if (value === '') {
            callback(new Error('请输入手机号'));
          } else if(!/^1[0-9]{10}$/.test(value)){
            callback(new Error('请输入正确的手机号'));
          } else {
            callback();
          }
        };
        var validatePass = (rule, value, callback) => {
          if(this.uid == 0){
            if (value === '') {
              callback(new Error('请输入密码'));
            } else if(value.length < 6){
              callback(new Error('密码不能小于6位'));
            } else {
              if (this.form.checkPass !== '') {
                this.$refs.ruleForm.validateField('checkPass');
              }
              callback();
            }
          }else if(this.form.password){
            if (value === '') {
              callback(new Error('请输入密码'));
            } else if(value.length < 6){
              callback(new Error('密码不能小于6位'));
            } else {
              if (this.form.checkPass !== '') {
                this.$refs.ruleForm.validateField('checkPass');
              }
              callback();
            }
          }else{
             callback();
          }
        };
        var validatePass2 = (rule, value, callback) => {
          if (value === '') {
            callback(new Error('请再次输入密码'));
          } else if (value !== this.form.password) {
            callback(new Error('两次输入密码不一致!'));
          } else {
            callback();
          }
        };

        var validateOldPwd = (rule, value, callback) => {
          if (value === '') {
            callback(new Error('请输入原密码'));
          } else if (hex_md5(value) !== this.oldPassword) {
            callback(new Error('密码错误!'));
          } else {
            callback();
          }
        };

      return {
        oldPassword: "",  //编辑时,记录旧密码
        form: {
          name: "",
          password: "",
          checkPass: "",
          phone: "",
          opwd: ""
        },
        formLabelWidth: '80px',
        rules: {
          name: [
            { validator: validateUsername, trigger: 'blur' }
          ],
          phone: [
            { validator: validatePhone, trigger: 'blur' }
          ],
          password: [
            { validator: validatePass, trigger: 'blur' }
          ],
          checkPass: [
            { validator: validatePass2, trigger: 'blur' }
          ],
          opwd: [
            { validator: validateOldPwd, trigger: 'blur' }
          ]
        }
      }
    },
    methods: {
      /**
       * 获取提交的数据
       * @date 2022/10/22
       */
      getParam(){
        let data = {};
        if(this.form['name']){
          data['name'] = this.form.name;
        }
        if(this.form['password']){
          data['password'] = this.form.password;
        }
        if(this.form['phone']){
          data['phone'] = this.form.phone;
        }
        return data;
      },
      /**
       * 添加用户信息
       * @date 2022/10/22
       */
      addUserInfo(){
        addUserInfo(this.getParam()).then(() => {
          this.$emit('saveSuccessChange', {});
          this.closeEvent();
        }).catch(e => {
          this.$message.error(e.msg);
        });
      },
      /**
       * 提交表单
       */
      submitForm(){
        this.$refs['ruleForm'].validate((valid) => {
          if(valid){
            this.addUserInfo();
          }else{
            return false;
          }
        });
      },
      /**
       * 关闭事件
       */
      closeEvent(){
        this.$refs['ruleForm'].resetFields();
        this.$emit('closeChange', {});
      },
    }
  }
</script>

        新增弹框组件创建完成后,我们在列表页(pages/mange/index.vue)中引入该组件,在打开新增用户弹框前,将selectId 置为0表示为新增。代码如下:

import UserDailog from '@/components/UserDailog'

export default {
  data () {
    return {
      //选择ID
      selectId: 0,
      //查询关键字
      keyword: "",
      /**
       * 是否显示弹框
       */
      isShowDialog: false,
      /**
       * 列表数据
       */
      tableList: [],
      /**
       * 选的项
       */
      multipleSelection: []
    }
  },
  components: {
    UserDailog
  },

  //...

  methods: {
     /**
     * 关闭弹框
     */
    closeChange(){
      this.isShowDialog = false;
    },

    /**
     * 新增用户信息
     */
    addUserEvent(){
      this.selectId = 0;
      this.isShowDialog = true;
    },

    //...
  }
}

        列表html部分引入组件,代码如下:

<UserDailog :visible="isShowDialog" 
    :uid="selectId" 
    @closeChange="closeChange" 
    @saveSuccessChange="updateUserList"
></UserDailog>

        并在新增按钮添加打开弹框事件,代码如下:

<el-button size="small" type="primary" @click="addUserEvent">新增</el-button>

        此时,我们可以看到新增弹框界面了,如下图:

         现在可以添加多条数据,进行筛选操作了。如添加test1、test2、test3、tom1、tom2,创建完后列表如下图:

         当我们在账号输入框中输入test,点击查询则只会显示包含test的账号,如下图:

        在账号输入框中输入tom,点击查询则只会显示包含tom的账号,如下图:

 

         这里列表查询、条件筛选和新增用户功能则完成了,接下来我们需要来完成修改数据功能。

1.3 修改数据

        在“1.2 新增数据”中,我们已经完成了db/model/user.js中的编辑部分的代码功能,这里我们只需要在pages/mange/index.vue中添加打开编辑弹框,并传入选中数据ID。代码如下:

methods: {
    /**
     * 编辑用户信息
     * @param {Object} id
     */
    editUserEvent(id){
      this.selectId = id;
      this.isShowDialog = true;
    },
}

        当弹框为编辑状态时,需要获取当前用户的信息,所在在db/model/user.js中需要添加通过ID获取用户信息的功能函数,直接通过get()函数获取指定用户信息即可。代码如下:

/**
 * 通过ID获取用户信息
 */
export const getUserInfoById = id => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName);
    //通过ID获取数据
    let data = store.get(id);

    data.onerror = function(e){
      reject(
        rJson(0, e, '查询出错了~')
      );
    }

    data.onsuccess = function(e){
      let result = e.target.result;
      if(result){
        delete result['accesstoken'];

        resolve(
          rJson(1, result, '获取成功~')
        )
      }else{
        reject(
          rJson(0, e, '数据不存在~')
        );
      }
    }
  });
}

        api/index.js中添加编辑和获取用户信息接口,代码如下:

import { toggleUser, getUserInfoById } from '@/db/model/user'

/**
 * 获取用户信息
 */
export const getUserById = id => {
  return getUserInfoById(id);
}

/**
 * 编辑用户信息
 */
export const editUserInfo = param => {
  return toggleUser(param);
}

        编辑的时候,不是所有信息都是必填的,其实在“1.2 新增数据”的JS部分代码中,已经完成此部分功能。用户的密码在修改时,是非必填的,只有填入新密码时才会交验;另外修改用户信息,需要输入原密码 进行校验,校验错误进无法进行保存。

        此时UserDialog/index.vue中的JS部分修改如下:

import { getUserById, addUserInfo, editUserInfo } from '@/api'
import { hex_md5 } from '@/utils/md5'
  export default {
    props: {
      //用户ID
      uid: {
        type: Number,
        default: () => 0
      },
      visible: {
        type: Boolean,
        default: () => false
      }
    },
    data(){
        var validateUsername = (rule, value, callback) => {
          if (value === '') {
            callback(new Error('请输入用户名'));
          } else {
            callback();
          }
        };
        var validatePhone = (rule, value, callback) => {
          if (value === '') {
            callback(new Error('请输入手机号'));
          } else if(!/^1[0-9]{10}$/.test(value)){
            callback(new Error('请输入正确的手机号'));
          } else {
            callback();
          }
        };
        var validatePass = (rule, value, callback) => {
          if(this.uid == 0){
            if (value === '') {
              callback(new Error('请输入密码'));
            } else if(value.length < 6){
              callback(new Error('密码不能小于6位'));
            } else {
              if (this.form.checkPass !== '') {
                this.$refs.ruleForm.validateField('checkPass');
              }
              callback();
            }
          }else if(this.form.password){
            if (value === '') {
              callback(new Error('请输入密码'));
            } else if(value.length < 6){
              callback(new Error('密码不能小于6位'));
            } else {
              if (this.form.checkPass !== '') {
                this.$refs.ruleForm.validateField('checkPass');
              }
              callback();
            }
          }else{
             callback();
          }
        };
        var validatePass2 = (rule, value, callback) => {
          if (value === '') {
            callback(new Error('请再次输入密码'));
          } else if (value !== this.form.password) {
            callback(new Error('两次输入密码不一致!'));
          } else {
            callback();
          }
        };

        var validateOldPwd = (rule, value, callback) => {
          if (value === '') {
            callback(new Error('请输入原密码'));
          } else if (hex_md5(value) !== this.oldPassword) {
            callback(new Error('密码错误!'));
          } else {
            callback();
          }
        };

      return {
        oldPassword: "",  //编辑时,记录旧密码
        form: {
          name: "",
          password: "",
          checkPass: "",
          phone: "",
          opwd: ""
        },
        formLabelWidth: '80px',
        rules: {
          name: [
            { validator: validateUsername, trigger: 'blur' }
          ],
          phone: [
            { validator: validatePhone, trigger: 'blur' }
          ],
          password: [
            { validator: validatePass, trigger: 'blur' }
          ],
          checkPass: [
            { validator: validatePass2, trigger: 'blur' }
          ],
          opwd: [
            { validator: validateOldPwd, trigger: 'blur' }
          ]
        }
      }
    },
    watch: {
      uid(){
        if(this.uid!=0){
          this.updateUserInfo();
        }
      }
    },
    methods: {
      /**
       * 获取用户信息
       */
      updateUserInfo(){
        getUserById(this.uid).then(res => {
          if(res.code==1&&res['data']){
            this.form['name'] = res.data.name;
            this.form['phone'] = res.data.phone;
            this.oldPassword = res.data.password;
          }
        }).catch(e => {
          this.$message.error(e.msg);
          this.closeEvent();
          // console.error(e);
        })
      },
      /**
       * 获取提交的数据
       */
      getParam(){
        let data = {};
        if(this.form['name']){
          data['name'] = this.form.name;
        }
        if(this.form['password']){
          data['password'] = this.form.password;
        }
        if(this.form['phone']){
          data['phone'] = this.form.phone;
        }
        return data;
      },
      /**
       * 添加用户信息
       */
      addUserInfo(){
        addUserInfo(this.getParam()).then(() => {
          this.$emit('saveSuccessChange', {});
          this.closeEvent();
        }).catch(e => {
          this.$message.error(e.msg);
        });
      },
      /**
       * 编辑用户信息
       */
      editUserInfo(){
        editUserInfo({
          id: this.uid,
          ...this.getParam()
        }).then(() => {
          this.$emit('saveSuccessChange', {});
          this.closeEvent();
        }).catch(e => {
          this.$message.error(e.msg);
        });
      },
      /**
       * 提交表单
       */
      submitForm(){
        this.$refs['ruleForm'].validate((valid) => {
          if(valid){
            //新增用户
            if(this.uid==0){
              this.addUserInfo();
            }
            //编辑用户
            else{
              this.editUserInfo();
            }
          }else{
            return false;
          }
        });
      },
      /**
       * 关闭事件
       */
      closeEvent(){
        this.$refs['ruleForm'].resetFields();
        this.$emit('closeChange', {});
      },
    }
  }

        编辑界面如下图:

        当我们需要修改用户名或手机号是,是必须输入原密码才能校验成功并进行保存。当密码框输入新密码后,则会显示再次确认密码框,不输入则非必填项。如将tom2修改为Peter,则列表则会更新为最新数据,如下图:

1.4 删除某条数据

        删除单表数据,直接通过delete(’id‘)即可,在db/model/user.js中添加deleteUserById函数,代码如下:

/**
 * 通过ID删除用户信息
 */
export const deleteUserById = id => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
    //删除指定用户信息
    let res = store.delete(id);
    res.onerror = function(e){
      reject(
        rJson(0, e, '操作出错了~')
      );
    }

    res.onsuccess = function(){
      resolve(
        rJson(1, null, '删除成功~')
      )
    }
  });
}

        api/index.js添加deleteUserInfo函数,代码如下:

import { deleteUserById } from '@/db/model/user'

/**
 * 删除用户信息
 */
export const deleteUserInfo = id => {
  return deleteUserById(id);
}

        pages/mange/index.vue中添加删除方法,代码如下:

methods: {
     /**
     * 删除用户信息
     * @param {Object} id
     */
    deleteEvent(id){
      this.$confirm('确认要删除该用户吗?', '提示', {
        confirmButtonText: '删除',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(res => {
        deleteUserInfo(id).then(() => {
          this.$message.success('删除成功!');
          this.updateUserList();
        }).catch(e => {
          this.$message.error(e.msg);
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    }
}

        给表格中的删除按钮绑定删除事件,代码如下:

<el-button type="danger" 
    size="mini" 
    :disabled="userInfo.id==scope.row.id" 
    icon="el-icon-delete" 
    circle 
    @click="deleteEvent(scope.row.id)"
    ></el-button>

        删除成功后,调用updateUserList()函数刷新数据列表即可。

1.5 删除选中多条数据

        删除多项则需要使用到游标相关知识点了,在db/model/user.js中添加deleteUserByIds函数,用来删除多条数据记录。通过openCursor()函数,对用户表进行遍历,通过includes判断遍历数据ID是否在删除数组中,在则直接调用delete()函数(注:这里不需要指定唯一ID,当前游标指向当前遍历数据实例对象)。

/**
 * 通过ID删除多条用户信息
 */
export const deleteUserByIds = ids => {
  return new Promise((resolve, reject) => {
    if(Array.isArray(ids)){
      //打开游标
      let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
      //打开游标
      let cursor = store.openCursor();

      cursor.onerror = function(e){
        reject(
          rJson(0, e, '操作出错了~')
        );
      }

      cursor.onsuccess = function(e){
        let result = e.target.result;
        if(result){
          if(ids.includes(result.key)){
            result.delete();
          }
          result.continue();
        }else{
          resolve(
             rJson(1, null, '删除成功~')
          )
        }
      }
    }else{
      reject(
        rJson(0, e, '请传入数组形式ID数据~')
      );
    }
    //end
  });
}

        api/index.js中添加删除多项数据功能函数,代码如下:

import { deleteUserByIds } from '@/db/model/user'

/**
 * 删除选择中项的用户信息
 */
export const deleteUserChecked = ids => {
  return deleteUserByIds(ids);
}

        pages/mange/index.vue中添加删除多项数据的方法,代码如下:

methods: {
    /**
     * 删除选中的ID项
     */
    deleteSelectedUser(){
      if(this.multipleSelection.length==0){
        this.$message({
          type: 'info',
          message: '请选择删除项'
        });
        return;
      }

      this.$confirm('确认要删除选中的用户吗?', '提示', {
        confirmButtonText: '删除',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(res => {
        deleteUserChecked(this.multipleSelection.map(item => item.id)).then(() => {
          this.$message.success('删除成功!');
          this.updateUserList();
        }).catch(e => {
          this.$message.error(e.msg);
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    }

}

        再给多项删除按钮添加绑定事件,代码如下:

<el-button size="small" type="danger" @click="deleteSelectedUser">删除</el-button>

        到此为止,用户管理的增删除改查功能就全部完成了;这里讲解比较碎片化,如果不清楚地方,可以留言询问;如有不足之处,欢迎指出。

二、年级管理

        年级管理的增删改查就不细讲了,增删改查也不复杂,可以按照“一、管理员列表” 中的功能进行复制,修改相应参数数据即可,都是大同小异。

       2.1 数据库操作文件

        创建db/model/grade.js,代码如下:

import { DBIsLoadSuccess, openTransactionIndex, CONST_READ } from '@/db'
import { rJson } from '@/utils/utils'

let storeName = 'grade';

/**
 * 获取年级列表
 */
export const loadGradeAllList = name => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName);
    //获取所有数据
    let alls = store.getAll();

    alls.onerror = function(e){
      reject(
        rJson(0, e, '查询出错了~')
      );
    }

    alls.onsuccess = function(e){
      let result = e.target.result;
      if(result){
        let rData = result;
        if(name){
          rData = result.filter(item => item.name.includes(name));
        }
        resolve(
          rJson(1, rData, '获取成功~')
        )
      }else{
        reject(
          rJson(0, null, '未查询到数据~')
        )
      }
      // console.log('store', result);
    }

  });
}


/**
 * 增加 或 编辑 年级信息
 */
export const toggleGrade = data => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store, index} = openTransactionIndex(storeName, 'name', CONST_READ.READWRITE);

    let res;

    //用户ID存在,则为编辑
    if(data['id']&&data.id!=0){
      data['updatetime'] = new Date().getTime();

      //获取原数据
      res = store.get(data.id);

      res.onerror = function(e){
        reject(
          rJson(0, e, '查询出错了~')
        );
      }

      res.onsuccess = function(e){
        let result = e.target.result;
        if(result){
          //合并数据,并保存
          res = store.put(Object.assign(result, data));

          res.onerror = function(e){
            reject(
              rJson(0, e, '查询出错了~')
            );
          }

          res.onsuccess = function(){
            resolve(
              rJson(1, null, '保存成功~')
            )
          }
        }else{
          reject(
            rJson(0, e, '年级不存在~')
          );
        }
      }

    }
    //新增(需要判断用户名是否已存在)
    else{
      //通过索引 获取用户名,判断用户名是否已存在
      res = index.getKey(data.name);

      res.onerror = function(e){
        reject(
          rJson(0, e, '查询出错了~')
        );
      }

      res.onsuccess = function(e){
        let result = e.target.result;
        //如果用户名已存在,返回错误信息
        if(result){
          reject(
            rJson(0, e, '该年级已存在~')
          );
        }
        //用户名不存在,则直接添加
        else{

          data['createtime'] = new Date().getTime();
          data['updatetime'] = new Date().getTime();
          res = store.add(data);

          res.onerror = function(e){
            reject(
              rJson(0, e, '查询出错了~')
            );
          }

          res.onsuccess = function(){
            resolve(
              rJson(1, null, '保存成功~')
            )
          }
        }

      }

    }

  });
}

/**
 * 通过ID删除 年级信息
 */
export const deleteGradeById = id => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
    //删除指定用户信息
    let res = store.delete(id);
    res.onerror = function(e){
      reject(
        rJson(0, e, '操作出错了~')
      );
    }

    res.onsuccess = function(){
      resolve(
        rJson(1, null, '删除成功~')
      )
    }
  });
}

/**
 * 通过ID删除多条 年级信息
 */
export const deleteGradeByIds = ids => {
  return new Promise((resolve, reject) => {
    if(Array.isArray(ids)){
      //打开游标
      let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
      //打开游标
      let cursor = store.openCursor();

      cursor.onerror = function(e){
        reject(
          rJson(0, e, '操作出错了~')
        );
      }

      cursor.onsuccess = function(e){
        let result = e.target.result;
        if(result){
          if(ids.includes(result.key)){
            result.delete();
          }
          result.continue();
        }else{
          resolve(
             rJson(1, null, '删除成功~')
          )
        }
      }
    }else{
      reject(
        rJson(0, e, '请传入数组形式ID数据~')
      );
    }
  });
}

       2.2 api接口

        api/index.js中添加年级部分接口函数,代码如下:

import {
  loadGradeAllList,
  toggleGrade,
  deleteGradeById,
  deleteGradeByIds
} from '@/db/model/grade'

/**
 * 获取年级列表
 */
export const gradeAllList = keyword => {
  return loadGradeAllList(keyword);
}

/**
 * 添加 或 修改指定年级信息
 */
export const toggleGradeInfo = name => {
  return toggleGrade(name);
}

/**
 * 删除指定年级
 */
export const deleteGradeInfo = id => {
  return deleteGradeById(id);
}

/**
 * 删除指定多项年级信息
 */
export const deleteGradeChecked  = ids => {
  return deleteGradeByIds(ids);
}

       2.3 列表页面

        打开年级列表页面pages/grade/index.vue,添加html、样式和JS部分功能。

        html代码部分:

<template>
<div class="index-wrap">
  <el-breadcrumb separator-class="el-icon-arrow-right">
    <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
    <el-breadcrumb-item>年级列表</el-breadcrumb-item>
  </el-breadcrumb>
  <br /><br />
  <div class="filter-wrap">
    <div class="item left">
      <el-form :inline="true" class="demo-form-inline">
        <el-form-item label="年级名称">
          <el-input size="small" v-model="keyword" placeholder="请输入年级名称"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button size="small" type="primary" @click="updateList">查询</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div class="item right">
      <el-form :inline="true" class="demo-form-inline">
        <el-form-item>
          <el-button size="small" type="primary" @click="addEvent">新增</el-button>
          <el-button size="small" type="info" @click="deleteCheckedEvent">删除</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>

  <div class="table-wrap">
    <el-table
      :data="tableList"
      @selection-change="selectionChange"
      style="width: 100%">
      <el-table-column type="selection" label="选择" width="50"> </el-table-column>
      <el-table-column prop="name" label="年级名称"></el-table-column>
      <el-table-column prop="createtime" label="创建日期"></el-table-column>
      <el-table-column prop="updatetime" label="更新日期"></el-table-column>
      <el-table-column label="操作" width="150">
        <template slot-scope="scope">
          <el-button type="primary" size="mini" icon="el-icon-edit" circle @click="editEvent(scope.row.id, scope.row.name)"></el-button>
          <el-button type="danger" size="mini" icon="el-icon-delete" circle @click="deleteEvent(scope.row.id)"></el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>

</div>
</template>

        样式部分:

.index-wrap{
  padding: 20px;
}

.filter-wrap{
  display: table;
  width: 100%;

  .item{
    display: table-cell;
    vertical-align: middle;

    &.left{
      text-align: left;
    }
    &.right{
      text-align: right;
    }
  }
}

        JS部分:

import { gradeAllList, toggleGradeInfo, deleteGradeInfo, deleteGradeChecked } from '@/api'
import { formatDate } from '@/utils/utils'

export default {
  data () {
    return {
      /**
       * 搜索关键词
       */
      keyword: "",
      /**
       * 列表数据
       */
      tableList: [],
      /**
       * 选中项
       */
      multipleSelection: []
    }
  },
  created() {
    this.updateList();
  },
  methods: {
    /**
     * 获取列表数据
     */
    updateList(){
      gradeAllList(this.keyword).then(res => {
        if(res.code==1&&Array.isArray(res.data)){
          this.tableList = res.data.map(item => {
            item['createtime'] = formatDate(item.createtime);
            item['updatetime'] = formatDate(item.updatetime);
            return item;
          });
        }
      }).catch(msg => {
        console.log('msg', msg);
      });
      //end
    },
    /**
     * 添加事件
     */
    addEvent(){
      this.$prompt('请输入年级名称', '提示', {
        confirmButtonText: '保存',
        cancelButtonText: '取消',
        inputValidator: function(value){
          if(value&&value.toString().length>0){
            return true;
          }else{
            return "请输入年级名称";
          }
        },
        inputErrorMessage: "请输入年级名称"
      }).then(({ value }) => {
        toggleGradeInfo({
          name: value
        }).then(res => {
          this.$message.success('添加成功');
          this.updateList();
        }).catch(e => {
          this.$message({
            type: 'info',
            message: e.msg
          });
        });
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消'
        });
      });
    },
    /**
     * 编辑事件
     */
    editEvent(id, name){
      this.$prompt('请输入年级名称', '提示', {
        confirmButtonText: '保存',
        cancelButtonText: '取消',
        inputValidator: function(value){
          if(value&&value.toString().length>0){
            return true;
          }else{
            return "请输入年级名称";
          }
        },
        inputValue: name,
        inputErrorMessage: "请输入年级名称"
      }).then(({ value }) => {
        toggleGradeInfo({
          id: id,
          name: value
        }).then(res => {
          this.$message.success('保存成功');
          this.updateList();
        }).catch(e => {
          this.$message({
            type: 'info',
            message: e.msg
          });
        });
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消'
        });
      });
    },
    /**
     * 删除事件
     * @param {Object} id
     */
    deleteEvent(id){
      this.$confirm('确认要删除该年级吗?', '提示', {
        confirmButtonText: '删除',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(res => {
        deleteGradeInfo(id).then(() => {
          this.$message.success('删除成功!');
          this.updateList();
        }).catch(e => {
          this.$message.error(e.msg);
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
    /**
     * check 选中项项值
     * @param {Object} val
     */
    selectionChange(val){
      this.multipleSelection = val;
    },
    /**
     * 删除多项指定年级信息
     */
    deleteCheckedEvent(){
      if(this.multipleSelection.length==0){
        this.$message({
          type: 'info',
          message: '请选择删除项'
        });
        return;
      }

      this.$confirm('确认要删除选中的年级吗?', '提示', {
        confirmButtonText: '删除',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(res => {
        deleteGradeChecked(this.multipleSelection.map(item => item.id)).then(() => {
          this.$message.success('删除成功!');
          this.updateList();
        }).catch(e => {
          this.$message.error(e.msg);
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    }
    //end
  }
}

        到此为止,年级部分功能就完成了;由于这里添加信息只有年级名称,所以使用了Element的this.$prompt弹框进行添加和编辑。界面效果如下:

列表页面:

新增页面:

三、教师列表

        这里先讲教师列表的功能实现,因为班级管理中需要关联对应班主任,这项为必填项;而教师对应的班级是非必填项。

        这部分和前面并无太大差异,还是常规的新删改查部分功能,所以也不作功能分解,直接按代码操作即可。

        3.1 数据库操作文件

        db/model/teacher.js代码如下:

import { DBIsLoadSuccess, openTransactionIndex, CONST_READ } from '@/db'
import { rJson } from '@/utils/utils'

let storeName = 'teacher';

/**
 * 获取 教师列表
 */
export const loadTeacherAllList = name => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName);
    //获取所有数据
    let alls = store.getAll();

    alls.onerror = function(e){
      reject(
        rJson(0, e, '查询出错了~')
      );
    }

    alls.onsuccess = function(e){
      let result = e.target.result;
      if(result){
        let rData = result;
        if(name){
          rData = result.filter(item => item.name.includes(name));
        }
        resolve(
          rJson(1, rData, '获取成功~')
        )
      }else{
        reject(
          rJson(0, null, '未查询到数据~')
        )
      }
      // console.log('store', result);
    }

  });
}


/**
 * 获取教师信息
 */
export const getTecharInfoById = id => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName);
    //通过ID获取数据
    let data = store.get(id);

    data.onerror = function(e){
      reject(
        rJson(0, e, '查询出错了~')
      );
    }

    data.onsuccess = function(e){
      let result = e.target.result;
      if(result){
        resolve(
          rJson(1, result, '获取成功~')
        )
      }else{
        reject(
          rJson(0, e, '数据不存在~')
        );
      }
    }
  });
}

/**
 * 增加 或 编辑 教师信息
 */
export const toggleTeacher = data => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store, index} = openTransactionIndex(storeName, 'name', CONST_READ.READWRITE);

    let res;
    //ID存在,则为编辑
    if(data['id']&&data.id!=0){
      data['updatetime'] = new Date().getTime();

      //获取原数据
      res = store.get(data.id);

      res.onerror = function(e){
        reject(
          rJson(0, e, '查询出错了~')
        );
      }

      res.onsuccess = function(e){
        let result = e.target.result;
        if(result){
          //合并数据,并保存
          res = store.put(Object.assign(result, data));

          res.onerror = function(e){
            reject(
              rJson(0, e, '查询出错了~')
            );
          }

          res.onsuccess = function(){
            resolve(
              rJson(1, null, '保存成功~')
            )
          }
        }else{
          reject(
            rJson(0, e, '年级不存在~')
          );
        }
      }

    }
    //新增(需要判断是否已存在)
    else{
      //通过索引获取,判断是否已存在
      res = index.getKey(data.name);

      res.onerror = function(){
        reject(
          rJson(0, e, '查询出错了~')
        );
      }

      res.onsuccess = function(e){
        let result = e.target.result;
        //如果已存在,返回错误信息
        if(result){
          reject(
            rJson(0, e, '该教师已存在~')
          );
        }
        //不存在,则直接添加
        else{

          data['createtime'] = new Date().getTime();
          data['updatetime'] = new Date().getTime();
          res = store.add(data);

          res.onerror = function(e){
            reject(
              rJson(0, e, '查询出错了~')
            );
          }

          res.onsuccess = function(){
            resolve(
              rJson(1, null, '保存成功~')
            )
          }
        }
        //if 2 end
      }

      //索引 End
    }

    //if end

  });
}

/**
 * 通过ID删除教师信息
 */
export const deleteTeacherById = id => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
    //删除指定信息
    let res = store.delete(id);
    res.onerror = function(e){
      reject(
        rJson(0, e, '操作出错了~')
      );
    }

    res.onsuccess = function(){
      resolve(
        rJson(1, null, '删除成功~')
      )
    }
  });
}

/**
 * 通过ID删除多条教师信息
 */
export const deleteTeacherByIds = ids => {
  return new Promise((resolve, reject) => {
    if(Array.isArray(ids)){
      //打开游标
      let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
      //打开游标
      let cursor = store.openCursor();

      cursor.onerror = function(e){
        reject(
          rJson(0, e, '操作出错了~')
        );
      }

      cursor.onsuccess = function(e){
        let result = e.target.result;
        if(result){
          if(ids.includes(result.key)){
            result.delete();
          }
          result.continue();
        }else{
          resolve(
             rJson(1, null, '删除成功~')
          )
        }
      }
    }else{
      reject(
        rJson(0, e, '请传入数组形式ID数据~')
      );
    }

  });
}

        3.2 api接口

        api/index.js文件添加以下代码:

import {
  loadTeacherAllList,
  toggleTeacher,
  deleteTeacherById,
  deleteTeacherByIds,
  getTecharInfoById
} from '@/db/model/teacher'

/**
 * 获取教师列表
 */
export const getTeachersList = name => {
  return loadTeacherAllList(name);
}

/**
 * 新增或修改教师信息
 */
export const toggerTeacherInfo = params => {
  return toggleTeacher(params);
}

/**
 * 通过ID获取教师信息
 */
export const loadTeacherById = id => {
  return getTecharInfoById(id);
}

/**
 * 单个教师信息删除
 */
export const deleteTeacherInfo = id => {
  return deleteTeacherById(id);
}

/**
 * 删除指定多个教师信息
 */
export const deleteSelectedTeacherInfo = ids => {
  return deleteTeacherByIds(ids);
}

        3.3 新增页面

        在components中添加TeacherDialog/index.vue新增页面组件,html部分代码:

<template>
  <el-dialog :title="uid!=0?'编辑':'新增'" :visible="visible" @close="closeEvent" width="420px" class="dialog-wrap">
    <el-form :model="form" :rules="rules"  status-icon ref="ruleForm">
      <el-form-item label="教师姓名" :label-width="formLabelWidth" required prop="name">
        <el-input v-model="form.name" autocomplete="off" size="small"></el-input>
      </el-form-item>
      <el-form-item label="户籍" :label-width="formLabelWidth" required prop="registration">
        <el-input v-model="form.registration" autocomplete="off" size="small"></el-input>
      </el-form-item>
      <el-form-item label="手机号" :label-width="formLabelWidth" required prop="phone">
        <el-input v-model="form.phone" autocomplete="off" size="small"></el-input>
      </el-form-item>
      <el-form-item label="居住地址" :label-width="formLabelWidth" required prop="address">
        <el-input v-model="form.address" autocomplete="off" size="small"></el-input>
      </el-form-item>
      <el-form-item label="出生日期" :label-width="formLabelWidth" required prop="birthday">
        <el-date-picker v-model="form.birthday" value-format="yyyy-MM-dd" type="date" placeholder="选择日期"></el-date-picker>
      </el-form-item>
    </el-form>

    <div slot="footer" class="dialog-footer">
      <el-button size="small" @click="closeEvent">取 消</el-button>
      <el-button size="small" type="primary" @click="submitForm">保 存</el-button>
    </div>

  </el-dialog>
</template>

js部分代码:

<script>
  import { toggerTeacherInfo, loadTeacherById } from '@/api'
  import { formatDate } from '@/utils/utils'
  export default {
    props: {
      //用户ID
      uid: {
        type: Number,
        default: () => 0
      },
      visible: {
        type: Boolean,
        default: () => false
      }
    },
    data(){
      return {
        formLabelWidth: '80px',
        gradeOptions: [],
        classOptions: [],
        dateValue: "",
        form: {
          name: "",
          registration: "",
          phone: "",
          address: "",
          birthday: ""
        },
        rules: {
          name: [
            { required: true, message: '请输入教师姓名', trigger: 'blur' },
             { required: true, message: '请输入教师姓名', trigger: 'change' },
          ],
          registration: [
             { required: true, message: '请输入户籍', trigger: 'blur' },
             { required: true, message: '请输入户籍', trigger: 'change' },
          ],
          phone: [
            { required: true, message: '请输入手机号', trigger: 'blur' },
             { required: true, message: '请输入手机号', trigger: 'change' },
             { tel: true, message: '请输入手机号', trigger: 'blur' },
             { tel: true, message: '请输入手机号', trigger: 'change' },
          ],
          address: [
            { required: true, message: '请输入现居住地址', trigger: 'blur' },
             { required: true, message: '请输入现居住地址', trigger: 'change' },
          ],
          birthday: [
            { required: true, message: '请选择出生日期', trigger: 'blur' },
            { required: true, message: '请选择出生日期', trigger: 'change' },
            { date: true, message: '请选择出生日期', trigger: 'blur' },
            { date: true, message: '请选择出生日期', trigger: 'change' },
          ]
        }
      }
    },
    watch: {
      uid(){
        if(this.uid!=0){
          this.updateClassInfo();
        }
      }
    },
    methods: {
      /**
       * 获取都老师信息
       */
      updateClassInfo(){
        loadTeacherById(this.uid).then(res => {
          if(res.code==1){
            this.form = {
              name: res.data['name'],
              registration: res.data['registration'],
              phone: res.data['phone'],
              address: res.data['address'],
              birthday: res.data['birthday']
            }
          }
        }).catch(e => {
          console.error(e);
        })
      },
      /**
       * 获取保存数据
       */
      getParams(){
        let { name, registration,  phone, address, birthday } = this.form;
        return {
          name, registration, phone, address, birthday
        }
      },
      /**
       * 添加教师信息
       */
      addUserInfo(){
        let param = this.getParams();
        toggerTeacherInfo(param).then(res => {
          if(res.code==1){
            this.$message.success('保存成功');
            this.$emit('saveChange', {});
          }
        }).catch(e => {
          this.$message.success(e.msg);
        });
      },
      /**
       * 编辑教师信息
       */
      editUserInfo(){
        let param = this.getParams();
        param['id'] = this.uid;
        toggerTeacherInfo(param).then(res => {
          if(res.code==1){
            this.$message.success('保存成功');
            this.$emit('saveChange', {});
          }
        }).catch(e => {
          this.$message.success(e.msg);
        });
      },
      /**
       * 提交表单
       */
      submitForm(){
        // console.log(this.form)
        this.$refs['ruleForm'].validate((valid) => {
          if(valid){
            //新增
            if(this.uid==0){
              this.addUserInfo();
            }
            //编辑
            else{
              this.editUserInfo();
            }
          }else{
            return false;
          }
        });
      },
      /**
       * 关闭事件
       */
      closeEvent(){
        this.$refs['ruleForm'].resetFields();
        this.$emit('closeChange', {});
      },
    }
  }
</script>

添加界面如下:

        3.4 列表页面

        在pages目录中teacher/index.vue添加列表页面,html部分代码如下:

<template>
<div class="index-wrap">
  <el-breadcrumb separator-class="el-icon-arrow-right">
    <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
    <el-breadcrumb-item>教师列表</el-breadcrumb-item>
  </el-breadcrumb>
  <br /><br />

  <div class="filter-wrap">
    <div class="item left">
      <el-form :inline="true" class="demo-form-inline">
        <el-form-item label="教师姓名">
          <el-input size="small" placeholder="请输入教师姓名" v-model="keyword"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button size="small" type="primary" @click="updateList">查询</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div class="item right">
      <el-form :inline="true" class="form-inline">
        <el-form-item>
          <el-button size="small" type="primary" @click="showAddDialog">新增</el-button>
          <el-button size="small" type="info" @click="deleteSelectedTeacher">删除</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>

  <div class="table-wrap">
    <el-table
      @selection-change="selectionChange"
      :data="tableList"
      style="width: 100%">
      <el-table-column type="selection" label="选择" width="50"> </el-table-column>
      <el-table-column prop="name" label="教师姓名"></el-table-column>
      <el-table-column prop="registration" label="户籍"></el-table-column>
      <el-table-column prop="address" label="居住地址"></el-table-column>
      <el-table-column prop="age" label="年龄" width="80">
        <template slot-scope="scope">
          <span>{{scope.row.birthday | filterAge}}</span>
        </template>
      </el-table-column>
      <el-table-column prop="createtime" label="创建日期" width="180"></el-table-column>
      <el-table-column prop="updatetime" label="更新日期" width="180"></el-table-column>
      <el-table-column label="操作" width="150">
        <template slot-scope="scope">
          <el-button type="primary" size="mini" icon="el-icon-edit" circle @click="editDialog(scope.row.id)"></el-button>
          <el-button type="danger" size="mini" icon="el-icon-delete" circle @click="deleteTeacherEvent(scope.row.id)"></el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>

  <TeacherDialog :uid="selectId" :visible="isShowDialog" @closeChange="closeChange" @saveChange="saveChange"></TeacherDialog>
</div>
</template>

js部分代码:

<script>
import TeacherDialog from '@/components/TeacherDialog'
import { getTeachersList, toggerTeacherInfo, deleteTeacherInfo, deleteSelectedTeacherInfo } from '@/api'
import { formatDate } from '@/utils/utils'

export default {
  data () {
    return {
      //编辑选择用户ID
      selectId: 0,
      //搜索关键词
      keyword: "",
      /**
       * 是否显示弹框
       */
      isShowDialog: false,
      /**
       * 列表数据
       */
      tableList: [],
      /**
       * 选择项
       */
      multipleSelection: []
    }
  },
  components: {
    TeacherDialog
  },
  created() {
    this.updateList();
  },
  filters: {
    filterAge(val){
      let current = new Date(),
          bDate = new Date(val);
      return current.getFullYear() - bDate.getFullYear();
    }
  },
  methods: {
    /**
     * 获取教师列表数据
     */
    updateList(){
      getTeachersList(this.keyword).then(res => {
        if(res.code==1){
          this.tableList = res.data.map(item => {
            item['createtime'] = formatDate(item.createtime);
            item['updatetime'] = formatDate(item.updatetime);
            return item;
          });
        }
        //if end
      }).catch(msg => {
        console.error(msg);
      });
      //ajax end
    },
    /**
     * 编辑教师信息
     */
    editDialog(id){
      this.selectId = id;
      this.isShowDialog = true;
    },
    /**
     * 显示弹框事件
     */
    showAddDialog(){
      this.isShowDialog = true;
    },
    /**
     * 新增教师保存事件
     */
    saveChange(){
      this.updateList();
      this.isShowDialog = false;
    },
    /**
     * 关闭弹框事件
     */
    closeChange(){
      this.selectId = 0;
      this.isShowDialog = false;
    },
    /**
     * 删除指定教师信息
     * @param {Object} id
     */
    deleteTeacherEvent(id){
      this.$confirm('确认要删除该教师信息吗?', '提示', {
        confirmButtonText: '删除',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(res => {
        deleteTeacherInfo(id).then(() => {
          this.$message.success('删除成功!');
          this.updateList();
        }).catch(e => {
          this.$message.error(e.msg);
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
    /**
     * check 选中项项值
     * @param {Object} val
     */
    selectionChange(val){
      this.multipleSelection = val;
    },
    /**
     * 删除指定多个教师信息
     */
    deleteSelectedTeacher(){
      if(this.multipleSelection.length==0){
        this.$message({
          type: 'info',
          message: '请选择删除项'
        });
        return;
      }

      this.$confirm('确认要删除选中的教师信息吗?', '提示', {
        confirmButtonText: '删除',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(res => {
        deleteSelectedTeacherInfo(this.multipleSelection.map(item => item.id)).then(() => {
          this.$message.success('删除成功!');
          this.updateList();
        }).catch(e => {
          this.$message.error(e.msg);
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    }
    //
  }
}
</script>

列表界面如下:

四、班级管理

        班级这部分由于关联了教师ID和年级ID,所以在做查询时,会稍微复杂点,同时需要之前的grade.js和teacher.js中增加单独查询功能,下面会一一阐述。

4.1 数据库操作文件

        db/model/classify.js代码:

import { DBIsLoadSuccess, openTransactionIndex, CONST_READ } from '@/db'
import { rJson } from '@/utils/utils'
import { getTeacherByIdsCursor } from './teacher.js'
import { getGradeByIdsCursor } from './grade.js'

let storeName = 'classify';

/**
 * 获取 班级信息
 */
export const loadClassAllList = async (name) => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName);
    //获取所有数据
    let alls = store.getAll();

    alls.onerror = function(e){
      console.log('error', e)
      reject(
        rJson(0, e, '查询出错了~')
      );
    }

    alls.onsuccess = function(e){
      let result = e.target.result;
      if(result){
        let rData = result;
        if(name){
          rData = result.filter(item => item.name.includes(name));
        }

        resolve(
          rJson(1, rData, '获取成功~')
        )
      }else{
        reject(
          rJson(0, null, '未查询到数据~')
        )
      }
      // console.log('store', result);
    }

  });
}

/**
 * 通过ID获取 班级信息
 */
export const getClassInfoById = id => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName);
    //通过ID获取数据
    let data = store.get(id);

    data.onerror = function(e){
      reject(
        rJson(0, e, '查询出错了~')
      );
    }

    data.onsuccess = function(e){
      let result = e.target.result;
      if(result){
        resolve(
          rJson(1, result, '获取成功~')
        )
      }else{
        reject(
          rJson(0, e, '数据不存在~')
        );
      }
    }
  });
}


/**
 * 通过年级ID获取对应班级信息
 */
export const getClassInfoByKey = key => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store, cursor} = openTransactionIndex(storeName, 'gid'),
        reData = [];

    cursor.onerror = function(e){
      reject(
        rJson(0, e, '查询出错了~')
      );
    }

    cursor.onsuccess = function(e){
      let result = e.target.result;
      if(result){
        if(result.key==key){
          reData.push({
            id: result.value.id,
            name: result.value.name
          });
        }
        result.continue();
      }else{
        resolve(
          rJson(1, reData, '获取成功~')
        )
        // console.log('end')
      }
    }
  });
}

/**
 * 增加 或 编辑 班级信息
 */
export const toggleClass = data => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store, index} = openTransactionIndex(storeName, 'name', CONST_READ.READWRITE);

    let res;

    //ID存在,则为编辑
    if(data['id']&&data.id!=0){
      data['updatetime'] = new Date().getTime();

      //获取原数据
      res = store.get(data.id);

      res.onerror = function(e){
        reject(
          rJson(0, e, '查询出错了~')
        );
      }

      res.onsuccess = function(e){
        let result = e.target.result;
        if(result){
          //合并数据,并保存
          res = store.put(Object.assign(result, data));

          res.onerror = function(e){
            reject(
              rJson(0, e, '查询出错了~')
            );
          }

          res.onsuccess = function(){
            resolve(
              rJson(1, null, '保存成功~')
            )
          }
        }else{
          reject(
            rJson(0, e, '年级不存在~')
          );
        }
      }

    }
    //新增(需要判断是否已存在)
    else{
      //通过索引获取,判断是否已存在
      res = index.getKey(data.name);

      res.onerror = function(e){
        reject(
          rJson(0, e, '查询出错了~')
        );
      }

      res.onsuccess = function(e){
        let result = e.target.result;
        //如果已存在,返回错误信息
        if(result){
          reject(
            rJson(0, e, '该年级已存在~')
          );
        }
        //不存在,则直接添加
        else{

          data['createtime'] = new Date().getTime();
          data['updatetime'] = new Date().getTime();
          res = store.add(data);

          res.onerror = function(e){
            reject(
              rJson(0, e, '查询出错了~')
            );
          }

          res.onsuccess = function(){
            resolve(
              rJson(1, null, '保存成功~')
            )
          }
        }
        //if 2 end
      }

      //索引 End
    }

    //if end

  });
}

/**
 * 通过ID删除班级
 */
export const deleteClassById = id => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
    //删除指定信息
    let res = store.delete(id);
    res.onerror = function(e){
      reject(
        rJson(0, e, '操作出错了~')
      );
    }

    res.onsuccess = function(){
      resolve(
        rJson(1, null, '删除成功~')
      )
    }
  });
}

/**
 * 通过ID删除多条班级
 */
export const deleteClassByIds = ids => {
  return new Promise((resolve, reject) => {
    if(Array.isArray(ids)){
      //打开游标
      let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
      //打开游标
      let cursor = store.openCursor();

      cursor.onerror = function(e){
        reject(
          rJson(0, e, '操作出错了~')
        );
      }

      cursor.onsuccess = function(e){
        let result = e.target.result;
        if(result){
          if(ids.includes(result.key)){
            result.delete();
          }
          result.continue();
        }else{
          resolve(
             rJson(1, null, '删除成功~')
          )
        }
      }
    }else{
      reject(
        rJson(0, e, '请传入数组形式ID数据~')
      );
    }
    //end
  });
}

4.2 api接口

        api/index.js中添加班级接口,代码如下:

import {
  loadClassAllList,
  toggleClass,
  getClassInfoById,
  deleteClassById,
  deleteClassByIds,
  getClassInfoByKey
} from '@/db/model/classify'

/**
 * 获取班级列表
 */
export const getClassList = name => {
  return loadClassAllList(name);
}

/**
 * 新增或保存 班级信息
 */
export const toggleClassInfo = param => {
  return toggleClass(param);
}

/**
 * 通过索引获取对应班级信息
 */
export const getClassByKey = key => {
  return getClassInfoByKey(key);
}

/**
 * 获取班级信息 通过ID
 */
export const getClassifyById = id => {
  return getClassInfoById(id);
}

/**
 * 通过ID删除指定班级信息
 */
export const deleteClassInfoById = id => {
  return deleteClassById(id);
}

/**
 * 通过选择中的ID删除 班级信息
 */
export const deleteClassSelectedInfoByIds = ids => {
  return deleteClassByIds(ids);
}

4.3 新增班级页面

        在components目录中添加ClassDialog/index.vue新增页面组件,html部分代码:

<template>
  <el-dialog :title="uid!=0?'编辑':'新增'" :visible="visible" @close="closeEvent" width="420px" class="dialog-wrap">
    <el-form :model="form" :rules="rules"  status-icon ref="ruleForm">
      <el-form-item label="班级名称" :label-width="formLabelWidth" prop="name" required>
        <el-input v-model="form.name" autocomplete="off" size="small"></el-input>
      </el-form-item>
      <el-form-item label="选择年级" :label-width="formLabelWidth" prop="grade" required>
        <el-select  size="small" v-model="form.grade" placeholder="请选择">
            <el-option
              v-for="item in gradeOptions"
              :key="item.id"
              :label="item.name"
              :value="item.id">
            </el-option>
          </el-select>
      </el-form-item>
      <el-form-item label="班主任" :label-width="formLabelWidth" prop="master" required>
        <el-select  size="small" v-model="form.master" placeholder="请选择">
            <el-option
              v-for="item in masterOptions"
              :key="item.id"
              :label="item.name"
              :value="item.id">
            </el-option>
          </el-select>
      </el-form-item>
      <el-form-item label="授课老师">
        <el-table
            :data="courseList"
            size="mini"
            border
            style="width: 100%">
            <el-table-column  prop="name" label="名称">
            </el-table-column>
            <el-table-column label="教师名称" width="180">
              <template slot-scope="scope">
                <el-select size="small" v-model="scope.row.tid" placeholder="请选择">
                    <el-option
                      v-for="item in masterOptions"
                      :key="item.id"
                      :label="item.name"
                      :value="item.id">
                    </el-option>
                  </el-select>
              </template>
            </el-table-column>
          </el-table>
      </el-form-item>
    </el-form>
    <div slot="footer" class="dialog-footer">
      <el-button size="small" @click="closeEvent">取 消</el-button>
      <el-button size="small" type="primary" @click="submitForm">保 存</el-button>
    </div>
  </el-dialog>
</template>

        这里与其他新增页面不同之处在于加载时,同时需要获取年级和教师数据列表,用于下拉选项,这两个接口已在api/index.js定义过,直接调用即可。

        这里也作了些偷懒操作,每个班级所对应课程并未作动态添加功能,而是写死在新增页面。保存的时候是以数组形式存库的,所以在编辑的时候,通过班级ID获取到班级信息,需将拿到ts字段对应信息,重新赋值给courseList。

        js代码部分:

<script>
  import { gradeAllList, getTeachersList, toggleClassInfo, getClassifyById } from '@/api'
  export default {
    props: {
      //用户ID
      uid: {
        type: Number,
        default: () => 0
      },
      visible: {
        type: Boolean,
        default: () => false
      }
    },
    data(){
      return {
        formLabelWidth: '80px',
        gradeOptions: [],   //年级
        masterOptions: [],  //教师
        courseList: [
          {"name": "语文", "tid": ""},
          {"name": "数据", "tid": ""},
          {"name": "英文", "tid": ""},
        ],
        form: {
          name: "",
          master: "",
          grade: ""
        },
        rules: {
          name: [
            { required: true, message: '请输入班级名称', trigger: 'blur' },
             { required: true, message: '请输入班级名称', trigger: 'change' },
          ],
          grade: [
            { required: true, message: '请选择年级', trigger: 'blur' },
             { required: true, message: '请选择年级', trigger: 'change' },
          ],
          master: [
            { required: true, message: '请选择班主任', trigger: 'blur' },
             { required: true, message: '请选择班主任', trigger: 'change' },
          ],
        }
      }
    },
    watch: {
      uid(){
        if(this.uid!=0){
          this.updateClassInfo();
        }
      }
    },
    created() {
      this.updatePropsInfo();
    },
    methods: {
      /**
       * 获取班级信息
       */
      updateClassInfo(){
        getClassifyById(this.uid).then(res => {
          if(res.code==1){
            this.form = {
              name: res.data.name,
              master: res.data.mid,
              grade: res.data.gid
            }
            if(Array.isArray(res.data['ts'])&&res.data.ts.length>0){
              this.courseList = res.data.ts;
            }
          }
          // console.log(res);
        }).catch(e => {
          console.error(e);
        })
      },
      /**
       * 获取属性信息
       */
      updatePropsInfo(){
        Promise.all([gradeAllList(), getTeachersList()]).then(res => {
          let gradeList = res[0]['data'],
              teacherList = res[1]['data'];

          if(Array.isArray(gradeList)){
            this.gradeOptions = gradeList.map(item => item);
          }

          if(Array.isArray(teacherList)){
            this.masterOptions = teacherList;
          }
        }).catch(e => {
          console.error(e);
        })
      },

      /**
       * 添加班级信息
       */
      addUserInfo(){
        let params = this.getParams();
       toggleClassInfo(params).then(res => {
         if(res.code==1){
           this.$message.success('保存成功');
           this.$emit('saveSuccessChange', {});
         }
       }).catch(e => {
         this.$message.success(e.msg);
         console.error(e);
       });
      },
      /**
       * 编辑班级信息
       */
      editUserInfo(){
        let params = this.getParams();
        params['id'] = this.uid;
        toggleClassInfo(params).then(res => {
          if(res.code==1){
            this.$message.success('保存成功');
            this.$emit('saveSuccessChange', {});
          }
        }).catch(e => {
          this.$message.success(e.msg);
          console.error(e);
        });
      },
      /**
       * 获取保存参数
       */
      getParams(){
        let { name, grade, master } = this.form;
        return {
          name,
          gid: grade,
          mid: master,
          ts: this.courseList
        }
      },
      /**
       * 提交表单
       */
      submitForm(){
        this.$refs['ruleForm'].validate((valid) => {
          if(valid){
            //新增班级
            if(this.uid==0){
              this.addUserInfo();
            }
            //编辑班级
            else{
              this.editUserInfo();
            }
          }else{
            return false;
          }
        });
      },
      /**
       * 关闭事件
       */
      closeEvent(){
        this.$refs['ruleForm'].resetFields();
        this.courseList = this.courseList.map(item => {
          item['tid'] = "";
          return item;
        })
        this.$emit('closeChange', {});
      },
    }
  }
</script>

新增界面如下:

        

4.4 班级列表页

        在pages/classify/index.vue中添加列表页面,html代码如下:

<template>
<div class="index-wrap">
  <el-breadcrumb separator-class="el-icon-arrow-right">
    <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
    <el-breadcrumb-item>班级列表</el-breadcrumb-item>
  </el-breadcrumb>
  <br /><br />

  <div class="filter-wrap">
    <div class="item left">
      <el-form :inline="true" class="demo-form-inline">
        <el-form-item label="班级名称">
          <el-input size="small" placeholder="请输入班级名称" v-model="keyword"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button size="small" type="primary" @click="updateList">查询</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div class="item right">
      <el-form :inline="true" class="demo-form-inline">
        <el-form-item>
          <el-button size="small" type="primary" @click="showAddDialog">新增</el-button>
          <el-button size="small" type="info" @click="deleteSelectedClass">删除</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>

  <div class="table-wrap">
    <el-table
      @selection-change="selectionChange"
      :data="tableList"
      style="width: 100%">
      <el-table-column type="selection" label="选择" width="50"> </el-table-column>
      <el-table-column prop="name" label="班级名称"></el-table-column>
      <el-table-column prop="master" label="班主任"></el-table-column>
      <el-table-column prop="grade" label="年级"></el-table-column>
      <el-table-column prop="createtime" label="创建日期"></el-table-column>
      <el-table-column prop="updatetime" label="更新日期"></el-table-column>
      <el-table-column prop="trs" label="授课教师" type="expand" width="100px">
        <template slot-scope="scope">
          <el-table
            size="small"
            :show-header="false"
            :data="scope.row.ts"
            style="width: 100%">
              <el-table-column prop="name" width="100px"></el-table-column>
              <el-table-column prop="teacher"></el-table-column>
            </el-table>
        </template>
      </el-table-column>
      <el-table-column label="操作" width="150">
        <template slot-scope="scope">
          <el-button type="primary" size="mini" icon="el-icon-edit" circle @click="editClassEvent(scope.row.id)"></el-button>
          <el-button type="danger" size="mini" icon="el-icon-delete" circle @click="deleteEvent(scope.row.id)"></el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>

  <ClassDialog :visible="isShowDialog" :uid="selectedId" @closeChange="closeChange" @saveSuccessChange="saveSuccessChange"></ClassDialog>

</div>
</template>

js部分代码:

<script>
import ClassDialog from '@/components/ClassDialog'
import { formatDate } from '@/utils/utils'
import { getClassList, deleteClassInfoById, deleteClassSelectedInfoByIds } from '@/api'

export default {
  data () {
    return {
      //选中的ID
      selectedId: 0,
      //搜索关键事件
      keyword: "",
      /**
       * 是否显示弹框
       */
      isShowDialog: false,
      /**
       * 列表数据
       */
      tableList: [],
      /**
       * 选择项
       */
      multipleSelection: []
    }
  },
  components: {
    ClassDialog
  },
  created() {
    this.updateList();
  },
  methods: {
    /**
     * 更新地址
     */
    updateList(){
      getClassList(this.keyword).then(res => {
        if(res.code==1){
          this.tableList = res.data.map(item => {
            item['createtime'] = formatDate(item.createtime);
            item['updatetime'] = formatDate(item.updatetime);
            return item;
          });
          // console.log(this.tableList)
        }
      }).catch(e => {
        console.error(e);
      })
    },
    /**
     * 保存成功
     */
    saveSuccessChange(){
      this.updateList();
      this.isShowDialog = false;
    },
    /**
     * 显示弹框
     */
    showAddDialog(){
      this.isShowDialog = true;
    },
    /**
     * 关闭弹框
     */
    closeChange(){
      this.selectedId = 0;
      this.isShowDialog = false;
    },
    /**
     * 编辑班级信息
     */
    editClassEvent(id){
      this.selectedId = id;
      this.isShowDialog = true;
    },
    /**
     * 删除指定班级信息
     * @param {Object} id
     */
    deleteEvent(id){
      this.$confirm('确认要删除该班级信息吗?', '提示', {
        confirmButtonText: '删除',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(res => {
        deleteClassInfoById(id).then(() => {
          this.$message.success('删除成功!');
          this.updateList();
        }).catch(e => {
          this.$message.error(e.msg);
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
    /**
     * check 选中项项值
     * @param {Object} val
     */
    selectionChange(val){
      this.multipleSelection = val;
    },
    /**
     * 删除选中的班级信息
     */
    deleteSelectedClass(){
      if(this.multipleSelection.length==0){
        this.$message({
          type: 'info',
          message: '请选择删除项'
        });
        return;
      }

      this.$confirm('确认要删除选中的班级信息吗?', '提示', {
        confirmButtonText: '删除',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(res => {
        deleteClassSelectedInfoByIds(this.multipleSelection.map(item => item.id)).then(() => {
          this.$message.success('删除成功!');
          this.updateList();
        }).catch(e => {
          this.$message.error(e.msg);
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },

  }
}
</script>

列表界面如下:

4.5 查询关联数据 

        如上图所示,现在班主任和年级信息无法显示,因为这里我们保存的是教师ID和年级ID,所以现在需要在列表查询功能中,增加master和grade两个字段,将查询到对应的数据赋值即可。

        并且想要拿到对应id的name值,则需要去对应teacher表和grade表中进行查询,所以还要在对应表的操作文件中添加相应查询功能函数。通过传入的ID集进行匹配相应数据,并以ID为键名保存到新的变量值中,以便与教师列表中的ID相关联。

第一步:打开db/model/teacher.js,添加getTeacherByIdsCursor()函数,代码如下:

/**
 * 通过游标获取对应数据集
 */
export const getTeacherByIdsCursor = ids => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName);
    //通过ID获取数据
    let cursor = store.openCursor(),
        reData = {};

    cursor.onerror = function(e){
      reject();
    }

    cursor.onsuccess = function(e){
        let result = e.target.result;
        if(result){
          if(ids.includes(result.value.id)){
            reData[result.value.id] = result.value;
          }
          result.continue();
        }else{
          resolve(reData);
        }
    }
    //end
  });
}

第二步:打开db/model/grade.js,添加getGradeByIdsCursor()函数,代码如下:

/**
 * 通过游标获取对应数据集
 */
export const getGradeByIdsCursor = ids => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName);
    //通过ID获取数据
    let cursor = store.openCursor(),
        reData = {};

    cursor.onerror = function(e){
      reject();
    }

    cursor.onsuccess = function(e){
        let result = e.target.result;
        if(result){
          if(ids.includes(result.value.id)){
            reData[result.value.id] = result.value;
          }
          result.continue();
        }else{
          resolve(reData);
        }
    }
    //end
  });
}

第三步:打开db/model/classify.js文件,修改loadClassAllList()函数,代码如下:

/**
 * 获取 班级信息
 */
export const loadClassAllList = async (name) => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName);
    //获取所有数据
    let alls = store.getAll();

    alls.onerror = function(e){
      reject(
        rJson(0, e, '查询出错了~')
      );
    }

    alls.onsuccess = function(e){
      let result = e.target.result;
      if(result){
        let rData = result;
        if(name){
          rData = result.filter(item => item.name.includes(name));
        }

        let teacherIds = [];
        //拿到不重复的教师ID
        rData.forEach(item => {
          if(!teacherIds.includes(item.mid)){
            teacherIds.push(item.mid);
          }

          if(Array.isArray(item['ts'])&&item.ts.length>0){
            item.ts.forEach(sub => {
              if(!teacherIds.includes(sub.tid)){
                teacherIds.push(sub.tid);
              }
            });
          }
        })

        //查询关联数据
        Promise.all([
            getTeacherByIdsCursor(teacherIds), 
            getGradeByIdsCursor(rData.map(item => item.gid))
        ]).then(res => {
          let teacher = res[0],
              grade = res[1];

          //重组数据
          rData = rData.map(item => {
            if('undefined'!==typeof teacher[item.mid]){
              item['master'] = teacher[item.mid]['name'];
            }
            if('undefined'!==typeof grade[item.gid]){
              item['grade'] = grade[item.gid]['name'];
            }
            //查询到授课教师信息
            if(Array.isArray(item['ts'])&&item.ts.length>0){
              item.ts = item.ts.map(sub => {
                if('undefined'!==typeof teacher[sub.tid]){
                  sub['teacher'] = teacher[sub.tid]['name'];
                }
                return sub;
              })
            }
            return item;
          });

          resolve(
            rJson(1, rData, '获取成功~')
          )
        }).catch(e => {
          reject(
            rJson(0, null, '关联数据查询错误~')
          )
        });


      }else{
        reject(
          rJson(0, null, '未查询到数据~')
        )
      }
    }

  });
}

此时再查看列表页,班主任和年级信息则显示出来了,如下图:

五、学员列表

5.1 数据库操作文件

        db/model/student.js代码如下:

import { DBIsLoadSuccess, openTransactionIndex, CONST_READ } from '@/db'
import { rJson } from '@/utils/utils'
import { getClassByIdsCursor } from './classify.js'

let storeName = 'student';

/**
 * 获取 学员列表
 */
export const loadStudentAllList = name => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName);
    //获取所有数据
    let alls = store.getAll();

    alls.onerror = function(e){
      reject(
        rJson(0, e, '查询出错了~')
      );
    }

    alls.onsuccess = function(e){
      let result = e.target.result;
      if(result){
        let rData = result;
        if(name){
          rData = result.filter(item => item.name.includes(name));
        }

        resolve(
          rJson(1, rData, '获取成功~')
        )

      }else{
        reject(
          rJson(0, null, '未查询到数据~')
        )
      }
      // console.log('store', result);
    }

  });
}

/**
 * 获取学员信息
 */
export const getStudentInfoById = id => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName);
    //通过ID获取数据
    let data = store.get(id);

    data.onerror = function(e){
      reject(
        rJson(0, e, '查询出错了~')
      );
    }

    data.onsuccess = function(e){
      let result = e.target.result;
      if(result){
        resolve(
          rJson(1, result, '获取成功~')
        )
      }else{
        reject(
          rJson(0, e, '数据不存在~')
        );
      }
    }
  });
}

/**
 * 增加 或 编辑 员学信息
 */
export const toggleStudent = data => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store, index} = openTransactionIndex(storeName, 'name', CONST_READ.READWRITE);

    let res;
    //ID存在,则为编辑
    if(data['id']&&data.id!=0){
      data['updatetime'] = new Date().getTime();

      //获取原数据
      res = store.get(data.id);

      res.onerror = function(e){
        reject(
          rJson(0, e, '查询出错了~')
        );
      }

      res.onsuccess = function(e){
        let result = e.target.result;
        if(result){
          //合并数据,并保存
          res = store.put(Object.assign(result, data));

          res.onerror = function(){
            reject(
              rJson(0, e, '查询出错了~')
            );
          }

          res.onsuccess = function(){
            resolve(
              rJson(1, null, '保存成功~')
            )
          }
        }else{
          reject(
            rJson(0, e, '年级不存在~')
          );
        }
      }

    }
    //新增(需要判断是否已存在)
    else{
      //通过索引获取,判断是否已存在
      res = index.getKey(data.name);

      res.onerror = function(e){
        reject(
          rJson(0, e, '查询出错了~')
        );
      }

      res.onsuccess = function(e){
        let result = e.target.result;
        //如果用已存在,返回错误信息
        if(result){
          reject(
            rJson(0, e, '该学员已存在~')
          );
        }
        //不存在,则直接添加
        else{

          data['createtime'] = new Date().getTime();
          data['updatetime'] = new Date().getTime();
          res = store.add(data);

          res.onerror = function(){
            reject(
              rJson(0, e, '查询出错了~')
            );
          }

          res.onsuccess = function(){
            resolve(
              rJson(1, null, '保存成功~')
            )
          }
        }
        //if 2 end
      }

      //索引 End
    }

    //if end

  });
}

/**
 * 通过ID删除学员信息
 */
export const deleteStudentById = id => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
    //删除指定信息
    let res = store.delete(id);
    res.onerror = function(e){
      reject(
        rJson(0, e, '操作出错了~')
      );
    }

    res.onsuccess = function(){
      resolve(
        rJson(1, null, '删除成功~')
      )
    }
  });
}

/**
 * 通过ID删除多条学员信息
 */
export const deleteStudentByIds = ids => {
  return new Promise((resolve, reject) => {
    if(Array.isArray(ids)){
      //打开游标
      let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
      //打开游标
      let cursor = store.openCursor();

      cursor.onerror = function(e){
        reject(
          rJson(0, e, '操作出错了~')
        );
      }

      cursor.onsuccess = function(e){
        let result = e.target.result;
        if(result){
          if(ids.includes(result.key)){
            result.delete();
          }
          result.continue();
        }else{
          resolve(
             rJson(1, null, '删除成功~')
          )
        }
      }
    }else{
      reject(
        rJson(0, e, '请传入数组形式ID数据~')
      );
    }
    //end
  });
}

5.2 api接口

        api/index.js文件中新增学员相关接口,代码如下:

import {
  loadStudentAllList,
  toggleStudent,
  getStudentInfoById,
  deleteStudentById,
  deleteStudentByIds
} from '@/db/model/student'

/**
 * 获取学员列表数据
 */
export const getStudentList = name => {
  return loadStudentAllList(name);
}

/**
 * 通过ID获取学员信息
 */
export const loadStudentById = id => {
  return getStudentInfoById(id);
}

/**
 * 添加 或 修改学员数据
 */
export const toggleStudentInfo = params => {
  return toggleStudent(params);
}

/**
 * 通过ID删除指定学员信息
 */
export const deleteStudentInfoById = id => {
  return deleteStudentById(id);
}

/**
 * 删除选中的学员信息
 */
export const deleteStudentInfoByIds = ids => {
  return deleteStudentByIds(ids);
}

5.3 新增页面

        在components/StudentDialog/index.vue中添加新增页面,html代码如下:

<template>
  <el-dialog :title="uid!=0?'编辑':'新增'" :visible="visible" @close="closeEvent" width="420px" class="dialog-wrap">

    <el-form :model="form" :rules="rules"  status-icon ref="ruleForm">
      <el-form-item label="学员姓名" :label-width="formLabelWidth" required prop="name">
        <el-input v-model="form.name" autocomplete="off" size="small"></el-input>
      </el-form-item>
      <el-form-item label="户籍" :label-width="formLabelWidth" required prop="registration">
        <el-input v-model="form.registration" autocomplete="off" size="small"></el-input>
      </el-form-item>
      <el-form-item label="手机号" :label-width="formLabelWidth" required prop="phone">
        <el-input v-model="form.phone" autocomplete="off" size="small"></el-input>
      </el-form-item>
     <el-form-item label="年级" :label-width="formLabelWidth" prop="gid">
        <el-select v-model="form.gid" placeholder="请选择" @change="gradeChange">
            <el-option
              v-for="item in gradeOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value">
            </el-option>
          </el-select>
      </el-form-item>
      <el-form-item label="班级" :label-width="formLabelWidth" prop="cid">
        <el-select v-model="form.cid" placeholder="请选择">
            <el-option
              v-for="item in classOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value">
            </el-option>
          </el-select>
      </el-form-item>
      <el-form-item label="居住地址" :label-width="formLabelWidth" required prop="address">
        <el-input v-model="form.address" autocomplete="off" size="small"></el-input>
      </el-form-item>
      <el-form-item label="出生日期" :label-width="formLabelWidth" required prop="birthday">
        <el-date-picker v-model="form.birthday" value-format="yyyy-MM-dd" type="date" placeholder="选择日期"></el-date-picker>
      </el-form-item>
    </el-form>

    <div slot="footer" class="dialog-footer">
      <el-button size="small" @click="closeEvent">取 消</el-button>
      <el-button size="small" type="primary" @click="submitForm">保 存</el-button>
    </div>

  </el-dialog>
</template>

js代码如下:

<script>
  import { toggleStudentInfo, loadStudentById, gradeAllList, getClassByKey } from '@/api'
  import { formatDate } from '@/utils/utils'
  export default {
    props: {
      //用户ID
      uid: {
        type: Number,
        default: () => 0
      },
      visible: {
        type: Boolean,
        default: () => false
      }
    },
    data(){
      return {
        formLabelWidth: '80px',
        gradeOptions: [],
        classOptions: [],
        dateValue: "",
        form: {
          name: "",
          registration: "",
          phone: "",
          gid: "",
          cid: "",
          address: "",
          birthday: ""
        },
        rules: {
          name: [
            { required: true, message: '请输入学员姓名', trigger: 'blur' },
             { required: true, message: '请输入学员姓名', trigger: 'change' },
          ],
          registration: [
             { required: true, message: '请输入户籍', trigger: 'blur' },
             { required: true, message: '请输入户籍', trigger: 'change' },
          ],
          phone: [
            { required: true, message: '请输入手机号', trigger: 'blur' },
             { required: true, message: '请输入手机号', trigger: 'change' },
             { tel: true, message: '请输入手机号', trigger: 'blur' },
             { tel: true, message: '请输入手机号', trigger: 'change' },
          ],
          gid: [
             { required: true, message: '请选择年级', trigger: 'change' },
          ],
          cid: [
             { required: true, message: '请选择班级', trigger: 'change' },
          ],
          address: [
            { required: true, message: '请输入现居住地址', trigger: 'blur' },
             { required: true, message: '请输入现居住地址', trigger: 'change' },
          ],
          birthday: [
            { required: true, message: '请选择出生日期', trigger: 'blur' },
            { required: true, message: '请选择出生日期', trigger: 'change' },
            { date: true, message: '请选择出生日期', trigger: 'blur' },
            { date: true, message: '请选择出生日期', trigger: 'change' },
          ]
        }
      }
    },
    watch: {
      uid(){
        if(this.uid!=0){
          this.updateStudentInfo();
        }
      }
    },
    created() {
      this.updateGradeInfo();
    },
    methods: {
      /**
       * 获取年级信息
       */
      updateGradeInfo(){
        gradeAllList().then(res => {
          if(res.code==1){
            this.gradeOptions = res.data.map(item => {
              return {
                label: item.name,
                value: item.id
              };
            })
          }
        }).catch(e => {
          console.error(e);
        })
      },
      /**
       * 获取班级信息
       */
      updateClassInfo(){
        getClassByKey(this.form.gid).then(res => {
          if(res.code==1){
            this.classOptions = res.data.map(item => {
              return {
                label: item.name,
                value: item.id
              };
            })
          }
          // console.log('res', res);
        }).catch(e => {
          console.error(e);
        })
      },
      /**
       * 年级发生变化 
       */
      gradeChange(){
        this.form.cid = "";
        this.updateClassInfo();
      },
      /**
       * 获取班级
       */
      updateStudentInfo(){
        loadStudentById(this.uid).then(res => {
          console.log(res)
          if(res.code==1){
            let data = res.data,
                tmpData = {
                  name: res.data['name'],
                  registration: res.data['registration'],
                  phone: res.data['phone'],
                  // gid: "",
                  // cid: "",
                  address: res.data['address'],
                  birthday: res.data['birthday']
                };

            if(data['gid']){
              tmpData['gid'] = data.gid;
            }
            if(data['cid']){
              tmpData['cid'] = data.cid;
            }
            this.form = tmpData;

            if(data['gid']){
              this.updateClassInfo();
            }
          }
          // console.log(res);
        }).catch(e => {
          console.error(e);
        })
      },
      /**
       * 获取保存数据
       */
      getParams(){
        let { name, registration,  phone, address, birthday, gid, cid } = this.form;
        return {
          name, registration, phone, address, birthday, gid, cid
        }
      },
      /**
       * 添加班级信息
       */
      addUserInfo(){
        let param = this.getParams();
        toggleStudentInfo(param).then(res => {
          if(res.code==1){
            this.$message.success('保存成功');
            this.$emit('saveChange', {});
          }
          // console.log('success', res)
        }).catch(e => {
          this.$message.success(e.msg);
        });
      },
      /**
       * 编辑班级信息
       */
      editUserInfo(){
        let param = this.getParams();
        param['id'] = this.uid;
        toggleStudentInfo(param).then(res => {
          if(res.code==1){
            this.$message.success('保存成功');
            this.$emit('saveChange', {});
          }
          // console.log('success', res)
        }).catch(e => {
          this.$message.success(e.msg);
        });
      },
      /**
       * 提交表单
       */
      submitForm(){
        // console.log(this.form)
        this.$refs['ruleForm'].validate((valid) => {
          if(valid){
            //新增班级
            if(this.uid==0){
              this.addUserInfo();
            }
            //编辑班级
            else{
              this.editUserInfo();
            }
          }else{
            return false;
          }
        });
      },
      /**
       * 关闭事件
       */
      closeEvent(){
        this.$refs['ruleForm'].resetFields();
        this.$emit('closeChange', {});
      },
    }
  }
</script>

界面如下:

         这里需要注意的是,为新增功能时,先加载年级数据列表,这部分接口是在之前年级功能实现就已经定义了,直接调用即可;当年级数据变化选中即,通过年级ID查询到对应的班级列表数据即可,这块接口也是在api/index.js中定义过的。

        当为编辑功能时,获取到详情数据需判断年级ID是否存在,如果存在则需要通过年级ID查询 出对应班级数据列表。

5.4 列表页面

        在pages/student/index.vue中添加列表页面,html代码如下:

<template>
<div class="index-wrap">
  <el-breadcrumb separator-class="el-icon-arrow-right">
    <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
    <el-breadcrumb-item>学员列表</el-breadcrumb-item>
  </el-breadcrumb>
  <br /><br />

  <div class="filter-wrap">
    <div class="item left">
      <el-form :inline="true" class="demo-form-inline">
        <el-form-item label="学员姓名">
          <el-input size="small" placeholder="请输入学员姓名" v-model="keyword"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button size="small" type="primary" @click="updateList">查询</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div class="item right">
      <el-form :inline="true" class="demo-form-inline">
        <el-form-item>
          <el-button size="small" type="primary" @click="showAddDialog">新增</el-button>
          <el-button size="small" type="info" @click="deleteSelectedStudent">删除</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>

  <div class="table-wrap">
    <el-table
      @selection-change="selectionChange"
      :data="tableList"
      style="width: 100%">
      <el-table-column type="selection" label="选择" width="50"> </el-table-column>
      <el-table-column prop="name" label="学员姓名"></el-table-column>
      <el-table-column prop="registration" label="户籍"></el-table-column>
      <el-table-column prop="address" label="居住地址"></el-table-column>
      <el-table-column prop="classify" label="班级"></el-table-column>
      <el-table-column prop="age" label="年龄" width="80">
        <template slot-scope="scope">
          <span>{{scope.row.birthday | filterAge}}</span>
        </template>
      </el-table-column>
      <el-table-column prop="createtime" label="创建日期" width="160"></el-table-column>
      <el-table-column prop="updatetime" label="更新日期" width="160"></el-table-column>
      <el-table-column label="操作" width="150">
        <template slot-scope="scope">
          <el-button type="primary" size="mini" icon="el-icon-edit" circle @click="editEvent(scope.row.id)"></el-button>
          <el-button type="danger" size="mini" icon="el-icon-delete" circle @click="deleteEvent(scope.row.id)"></el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>

  <StudentDialog :visible="isShowDialog" :uid="selectId" @closeChange="closeDialog" @saveChange="saveChange"></StudentDialog>
</div>
</template>

js代码部分:

<script>
  import StudentDialog from '@/components/StudentDialog'
  import { getStudentList, deleteStudentInfoById, deleteStudentInfoByIds } from '@/api'
  import { formatDate } from '@/utils/utils'

export default {
  data () {
    return {
      //选中ID
      selectId: 0,
      //搜索关键词
      keyword: "",
      /**
       * 是否显示弹框
       */
      isShowDialog: false,
      /**
       * 列表数据
       */
      tableList: [],
      /**
       * 选择项
       */
      multipleSelection: []
    }
  },
  filters: {
    filterAge(val){
      let current = new Date(),
          bDate = new Date(val);
      return current.getFullYear() - bDate.getFullYear();
    }
  },
  components: {
    StudentDialog
  },
  created() {
    this.updateList();
  },
  methods: {
    /**
     * 获取列表数据
     */
    updateList(){
      getStudentList(this.keyword).then(res => {
        // console.log(res);
        if(res.code==1){
          this.tableList = res.data.map(item => {
            item['createtime'] = formatDate(item.createtime);
            item['updatetime'] = formatDate(item.updatetime);
            return item;
          });
        }
      }).catch(e => {
        console.error(e);
      })
    },
    /**
     * 显示弹框事件
     */
    showAddDialog(){
      this.isShowDialog = true;
    },
    /**
     * 关闭弹框
     */
    closeDialog(){
      this.selectId = 0;
      this.isShowDialog = false;
    },
    /**
     * 保存成功
     */
    saveChange(){
      this.updateList();
      this.isShowDialog = false;
    },
    /**
     * 编辑学员信息
     * @param {Object} id
     */
    editEvent(id){
      this.selectId = id;
      this.isShowDialog = true;
    },
    /**
     * 删除学员信息
     * @param {Object} id
     */
    deleteEvent(id){
      this.$confirm('确认要删除该学员信息吗?', '提示', {
        confirmButtonText: '删除',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(res => {
        deleteStudentInfoById(id).then(() => {
          this.$message.success('删除成功!');
          this.updateList();
        }).catch(e => {
          this.$message.error(e.msg);
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
    /**
     * check 选中项项值
     * @param {Object} val
     */
    selectionChange(val){
      this.multipleSelection = val;
    },
    /**
     * 删除选中的学员信息
     */
    deleteSelectedStudent(){
      if(this.multipleSelection.length==0){
        this.$message({
          type: 'info',
          message: '请选择删除项'
        });
        return;
      }

      this.$confirm('确认要删除选中的学员信息吗?', '提示', {
        confirmButtonText: '删除',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(res => {
        deleteStudentInfoByIds(this.multipleSelection.map(item => item.id)).then(() => {
          this.$message.success('删除成功!');
          this.updateList();
        }).catch(e => {
          this.$message.error(e.msg);
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
    //end
  }
}
</script>

界面效果如下:

5.5 关联数据查询

        这里出现同样的问题,关键班级的信息未显示出来,和班级中查询关联数据一样,以同样方式即可。

第一步:打开db\model\classify.js文件,添加getClassByIdsCursor()函数,代码如下:

/**
 * 通过游标获取对应数据集
 */
export const getClassByIdsCursor = ids => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName);
    //通过ID获取数据
    let cursor = store.openCursor(),
        reData = {};

    cursor.onerror = function(e){
      reject();
    }

    cursor.onsuccess = function(e){
        let result = e.target.result;
        if(result){
          if(ids.includes(result.value.id)){
            reData[result.value.id] = result.value;
          }
          result.continue();
        }else{
          resolve(reData);
        }
    }
    //end
  });
}

 第二步:打开db\model\student.js文件,修改loadStudentAllList()函数,代码如下:

/**
 * 获取 学员列表
 */
export const loadStudentAllList = name => {
  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName);
    //获取所有数据
    let alls = store.getAll();

    alls.onerror = function(e){
      reject(
        rJson(0, e, '查询出错了~')
      );
    }

    alls.onsuccess = function(e){
      let result = e.target.result;
      if(result){
        let rData = result;
        if(name){
          rData = result.filter(item => item.name.includes(name));
        }

        getClassByIdsCursor(rData.filter(item => item.cid).map(item => item.cid)).then(res => {
          rData = rData.map(item => {
            if('undefined'!==typeof res[item.cid]){
              item['classify'] = res[item.cid]['name'];
            }
            return item;
          })
          resolve(
            rJson(1, rData, '获取成功~')
          )
        }).catch(e => {
          reject(
            rJson(0, e, '查询出错了~')
          )
        });

      }else{
        reject(
          rJson(0, null, '未查询到数据~')
        )
      }

    }

  });
}

现在列表页面效果如下:

六、分页功能

        这里我们以学员列表为例,添加分页查询功能。注意的是,其他页面列表查询已在各关键页面中使用,为了避免影响别的功能,建议新建分页查询 函数。

6.1 分页功能函数

        首先打开src/utils/utils.js文件,添加分页功能函数,代码如下:

/**
 * 生成分页数据
 */
export const genderPage = (data, param) => {
  //判断分页数据是否存在,否则赋值默认参数
  param = param && 'undefined'!==typeof param['page'] && 'undefined'!==typeof param['pageSize'] ? param : {
		page: 1,
		pageSize: 10
	}
	let newData = data.map(item => item),
			start = (param.page - 1) * param.pageSize,
			end = newData.length - start < param.pageSize ? newData.length : start + param.pageSize;
	return newData.slice(start, end);
}

6.2 增加分页查询功能

        打开db/model/student.js,添加分页查询函数loadStudentPage(),代码如下:

import { DBIsLoadSuccess, openTransactionIndex, CONST_READ } from '@/db'
import { rJson, genderPage } from '@/utils/utils'
import { getClassByIdsCursor } from './classify.js'

let storeName = 'student';

/**
 * 获取 学员列表 - 分页模式
 * @param name 查询关键词
 * @param param 分页参数
 */
export const loadStudentPage = (name, param) => {

  return new Promise((resolve, reject) => {
    //打开游标
    let {store} = openTransactionIndex(storeName);
    //获取所有数据
    let alls = store.getAll();

    alls.onerror = function(e){
      reject(
        rJson(0, e, '查询出错了~')
      );
    }

    alls.onsuccess = function(e){
      let result = e.target.result;
      if(result){
        let rData = result;
        if(name){
          rData = result.filter(item => item.name.includes(name));
        }
        //查询班级关联数据
        getClassByIdsCursor(rData.filter(item => item.cid).map(item => item.cid)).then(res => {
          rData = rData.map(item => {
            if('undefined'!==typeof res[item.cid]){
              item['classify'] = res[item.cid]['name'];
            }
            return item;
          })

          //通过genderPageData函数进行分页处理
          resolve(
            rJson(1, {
              list: genderPage(rData, param),
              total: rData.length
            }, '获取成功~')
          )
        }).catch(e => {
          reject(
            rJson(0, e, '查询出错了~')
          )
        });

      }else{
        reject(
          rJson(0, null, '未查询到数据~')
        )
      }
    }

  });
}

6.3 api接口

        打开api/index.js,添加分页查询接口函数,代码如下:

import {
  loadStudentPage
} from '@/db/model/student'

/**
 * 获取学员列表数据 - 分页模式
 */
export const getStudentPageList = (name, param) => {
  return loadStudentPage(name, param);
}

6.4 添加分页代码

html部分,在列表下添加分页代码,代码如下:

<div class="table-wrap">
    ...

    <el-pagination
      background
      layout="prev, pager, next"
      @current-change="currentChange"
      :current-page="page"
      :page-size="pageSize"
      :total="pageTotal">
    </el-pagination>
  </div>

js部分,引入getStudentPageList接口函数,在data中添加分页参数,增加分页切换事件,代码如下:

 import StudentDialog from '@/components/StudentDialog'
  import { getStudentList, getStudentPageList, deleteStudentInfoById, deleteStudentInfoByIds } from '@/api'
  import { formatDate } from '@/utils/utils'

export default {
  data () {
    return {
      //...

      //分页参数
      page: 1,
      pageSize: 5,
      pageTotal: 0
    }
  },
  filters: {
    filterAge(val){
      let current = new Date(),
          bDate = new Date(val);
      return current.getFullYear() - bDate.getFullYear();
    }
  },
  components: {
    StudentDialog
  },
  created() {
    this.updateList();
  },
  methods: {
    /**
     * 当前页发生改变
     */
    currentChange(page){
      this.page = page;
      this.updateList();
    }
  }

6.5 修改列表查询函数

        由于分页查询功能中需要返回数据总量,则原来返回结果结构发生变化,所以updateList()函数需要稍微调整下,代码如下:

methods: {
    /**
     * 获取列表数据
     */
    updateList(){
      getStudentPageList(this.keyword, {
        page: this.page,
        pageSize: this.pageSize
      }).then(res => {
        if(res.code==1){
          this.pageTotal = res.data['total'];
          this.tableList = res.data['list'].map(item => {
            item['createtime'] = formatDate(item.createtime);
            item['updatetime'] = formatDate(item.updatetime);
            return item;
          });
        }
      }).catch(e => {
        console.error(e);
      })
    },

    //...
}

此时页面效果如下:

        到此为止,该系统开发则已经完结了,有兴趣的朋友可以再升级和优化下。

        由于近期工作原因,不是每天都能抽出时间开发,所以有些不太连贯,望见谅。此篇对增删改查也没作太多细讲,因为都差不多,大家可以拷贝代码到本地运行自行研究。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值