Local database IndexedDB - list management of student management system (2)

 IndexedDB is a local database provided by the browser, which can be created and operated by web scripts. IndexedDB allows storing large amounts of data, provides a search interface, and can also create indexes. These are not available in LocalStorage or Cookie. As far as the database type is concerned, IndexedDB is not a relational database (does not support SQL query statements), but is closer to a NoSQL database.

        Through the previous article "Local Database IndexedDB - Student Management System Login (1)", we have completed the login function of the system, and this chapter completes the related list management functions to realize administrator list, grade management, class management, Add, delete, modify and check columns such as teacher list and student list.

        Due to the busy work in the middle, the time between the release of the next article is long, and combined with the later development process, the definition content of the previous part has been modified. There are some differences. You can read the previous article again.

Previous address: Local Database IndexedDB - Student Management System Login (1)_Awakening Mage's Blog-CSDN Blog

        

1. List of administrators

        Before we start, we will fix the user login information in the previous chapter; when the user logs in successfully, the information will be cached in localStorage, and there will be only one copy in the local state manager; when managing the user list, encounter When it comes to the login user information, it is necessary to judge whether it can be modified or deleted, etc., and the user information needs to be obtained from the store, but after the page is refreshed, the user information in the store state will be lost. The user information in the cache is saved to the store state. Open the store/actions.js file and add the following code:

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 Get user list

        First, in db/model/user.js, we define the loadUserAllList user to load all user information; the filter user function can be filtered by passing in the name, and when obtaining all the data, it can be filtered by filter; in addition, here we first use getAll( ) method to get all the data, and we will explain how to perform pagination query later. code show as below:

/**
 * 获取用户列表
 */
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);
    }

  });
}

        The second step is to define the userAllList interface function in api/index.js, the code is as follows:

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


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

        html code:

<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>

        Style section:

.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 code part:

<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>

        After the above preparatory work is completed, our page will have user data, as shown in the figure below:

       You can observe that the multi-option and delete buttons of admin are disabled, because the currently logged-in user cannot delete himself. How to achieve it, the delete button is compared with the user ID fetched from the store and the list rendering user ID, and it is disabled if it is judged as the currently logged-in user; the multi-selection function is compared with the user ID in the store through the selectable function Judgmental.

        Of course, the list data is displayed now, but there is only one piece of data, which cannot be filtered by conditions. This piece will be operated after we complete the new function.

1.2 New data

        First, we define the toggleUser function in db/model/user.js to add or edit user information; when the data is new, first determine whether the user name already exists, and return an error message if it exists, and directly Add as a new user; when the data is edited, first obtain the original data of the user, merge the original data with the new data, and if you use put to save, it will overwrite the previously unmodified data.

        When editing, first obtain all the information of the user through the get() method, and then merge the data.

        When adding a new user, first judge whether the user exists through the name index, and return a prompt message if it exists; if it does not exist, add it directly.

code show as below:

/**
 * 增加 或 编辑用户信息
 */
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 adds addUserInfo() method, the code is as follows:

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

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

        Next, let's create a new popup component, create a UserDailog directory in the components directory, and add index.vue.

        The html code part of the bullet box page:

<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 code part:

<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>

        After the new popup component is created, we introduce the component into the list page (pages/mange/index.vue), and before opening the new user popup, set selectId to 0 to indicate new. code show as below:

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;
    },

    //...
  }
}

        The list html part introduces components, the code is as follows:

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

        And add the event of opening the popup box to the new button, the code is as follows:

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

        At this point, we can see the new pop-up interface, as shown below:

         Now you can add multiple pieces of data and perform filtering operations. For example, add test1, test2, test3, tom1, tom2, the list is as follows after creation:

         When we enter test in the account input box, and click Query, only the accounts containing test will be displayed, as shown in the figure below:

        Enter tom in the account input box, and click Query to display only the accounts containing tom, as shown in the figure below:

 

         Here the list query, conditional filtering and new user functions are completed, and then we need to complete the data modification function.

1.3 Modify data

        In "1.2 Adding new data", we have completed the code function of the editing part in db/model/user.js, here we only need to add the open editing pop-up box in pages/mange/index.vue, and pass in Check the data ID. code show as below:

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

        When the pop-up box is in the editing state, the current user information needs to be obtained. In db/model/user.js, a function function for obtaining user information through ID needs to be added, and the specified user information can be obtained directly through the get() function. code show as below:

/**
 * 通过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, '数据不存在~')
        );
      }
    }
  });
}

        Add an interface for editing and obtaining user information in api/index.js, the code is as follows:

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

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

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

        When editing, not all information is required. In fact, this part of the function has been completed in the JS part of the code in "1.2 New Data". When the user's password is modified, it is optional and will only be submitted for verification when the new password is filled in; in addition, to modify the user information, the original password needs to be entered for verification, and if the verification error occurs, it cannot be saved.

        At this time, the JS part in UserDialog/index.vue is modified as follows:

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', {});
      },
    }
  }

        The editing interface is as follows:

        When we need to modify the user name or mobile phone number, we must enter the original password to successfully verify and save it. When a new password is entered in the password box, a reconfirm password box will be displayed, and if it is not entered, it is not required. If tom2 is changed to Peter, the list will be updated with the latest data, as shown in the figure below:

1.4 Delete a piece of data

        To delete single-table data, just pass delete('id') directly, and add the deleteUserById function in db/model/user.js, the code is as follows:

/**
 * 通过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, '删除成功~')
      )
    }
  });
}

        Add deleteUserInfo function in api/index.js, the code is as follows:

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

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

        Add the delete method in pages/mange/index.vue, the code is as follows:

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: '已取消删除'
        });
      });
    }
}

        Bind the delete event to the delete button in the table, the code is as follows:

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

        After the deletion is successful, call the updateUserList() function to refresh the data list.

1.5 Delete selected multiple pieces of data

        To delete multiple items, you need to use cursor-related knowledge points. Add the deleteUserByIds function in db/model/user.js to delete multiple data records. Use the openCursor() function to traverse the user table, and use includes to determine whether the traversed data ID is in the deletion array, and then directly call the delete() function (Note: there is no need to specify a unique ID here, and the current cursor points to the current traversed data instance object ).

/**
 * 通过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
  });
}

        Add a function to delete multiple data in api/index.js, the code is as follows:

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

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

        Add the method of deleting multiple data in pages/mange/index.vue, the code is as follows:

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: '已取消删除'
        });
      });
    }

}

        Then add binding events to multiple delete buttons, the code is as follows:

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

        So far, the functions of adding, deleting, modifying and checking of user management have all been completed; the explanation here is relatively fragmented, if you don’t know the place, you can leave a message to ask; if there are any deficiencies, please point out.

Second grade management

        The addition, deletion, modification and query of grade management will not go into details, and the addition, deletion, modification and query are not complicated. You can copy them according to the functions in "1. Administrator list" and modify the corresponding parameter data. They are all similar.

       2.1 Database operation files

        Create db/model/grade.js with the following code:

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 interface

        Add the grade part interface function in api/index.js, the code is as follows:

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 List page

        Open the grade list page pages/grade/index.vue, add some functions of html, style and JS.

        html code part:

<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>

        Style section:

.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 part:

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
  }
}

        So far, the function of the grade part is completed; since the added information here is only the grade name, the this.$prompt pop-up box of Element is used to add and edit. The interface effect is as follows:

List page:

New page:

3. List of teachers

        Here we first talk about the realization of the function of the teacher list, because the class management needs to be associated with the corresponding head teacher, this is a required item; and the class corresponding to the teacher is not a required item.

        This part is not much different from the previous part, and it is still a regular function of adding, deleting, modifying and checking, so there is no function decomposition, just operate according to the code.

        3.1 Database operation files

        The db/model/teacher.js code is as follows:

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 interface

        Add the following code to the api/index.js file:

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 New page

        Add TeacherDialog/index.vue in components to add new page components, html part code:

<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 part of the code:

<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>

The interface for adding is as follows:

        3.4 List page

        Add a list page to teacher/index.vue in the pages directory, and the html code is as follows:

<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 part of the code:

<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>

The list interface is as follows:

4. Class Management

        Since the class part is associated with the teacher ID and grade ID, it will be a little more complicated when doing the query. At the same time, a separate query function needs to be added to the previous grade.js and teacher.js, which will be explained one by one below.

4.1 Database operation files

        db/model/classify.js code:

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 interface

        Add a class interface in api/index.js, the code is as follows:

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 Add a new class page

        Add ClassDialog/index.vue to the components directory to add new page components, html part code:

<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>

        The difference between this page and other newly added pages is that when loading, the grade and teacher data list needs to be obtained at the same time for the drop-down options. These two interfaces have been defined in api/index.js and can be called directly.

        There are also some lazy operations here. The courses corresponding to each class do not have dynamic addition functions, but are hard-coded on the new page. When saving, it is stored in the form of an array, so when editing, the class information is obtained through the class ID, and the corresponding information of the ts field needs to be reassigned to the courseList.

        js code part:

<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>

The newly added interface is as follows:

        

4.4 Class List Page

        Add a list page in pages/classify/index.vue, the html code is as follows:

<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 part of the code:

<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>

The list interface is as follows:

4.5 Query related data 

        As shown in the figure above, the head teacher and grade information cannot be displayed now, because here we save the teacher ID and grade ID, so now we need to add two fields master and grade in the list query function, and assign the corresponding data to the query. Can.

        And if you want to get the name value of the corresponding id, you need to query the corresponding teacher table and grade table, so you need to add the corresponding query function in the operation file of the corresponding table. Match the corresponding data through the incoming ID set, and save it into a new variable value with the ID as the key name, so as to associate with the ID in the teacher list.

Step 1: Open db/model/teacher.js, add getTeacherByIdsCursor() function, the code is as follows:

/**
 * 通过游标获取对应数据集
 */
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
  });
}

Step 2: Open db/model/grade.js, add getGradeByIdsCursor() function, the code is as follows:

/**
 * 通过游标获取对应数据集
 */
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
  });
}

Step 3: Open the db/model/classify.js file, modify the loadClassAllList() function, the code is as follows:

/**
 * 获取 班级信息
 */
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, '未查询到数据~')
        )
      }
    }

  });
}

At this time, check the list page again, and the class teacher and grade information will be displayed, as shown in the figure below:

5. List of students

5.1 Database operation files

        The db/model/student.js code is as follows:

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 interface

        Add a student-related interface in the api/index.js file, and the code is as follows:

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 New page

        Add a new page in components/StudentDialog/index.vue, the html code is as follows:

<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>

The js code is as follows:

<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>

The interface is as follows:

         It should be noted here that when adding new functions, first load the grade data list. This part of the interface has been defined before the grade function implementation, and it can be called directly; when the grade data change is selected, the corresponding grade ID can be queried. The class list data is enough, and this interface is also defined in api/index.js.

        When it is an editing function, to obtain the detailed data, it is necessary to determine whether the grade ID exists. If it exists, it is necessary to query the corresponding class data list through the grade ID.

5.4 List page

        Add a list page in pages/student/index.vue, the html code is as follows:

<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 code part:

<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>

The interface effect is as follows:

5.5 Linked Data Query

        The same problem occurs here, the information of the key class is not displayed, and it is the same as querying the associated data in the class, and it can be done in the same way.

Step 1: Open the db\model\classify.js file, add the getClassByIdsCursor() function, the code is as follows:

/**
 * 通过游标获取对应数据集
 */
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
  });
}

 Step 2: Open the db\model\student.js file, modify the loadStudentAllList() function, the code is as follows:

/**
 * 获取 学员列表
 */
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, '未查询到数据~')
        )
      }

    }

  });
}

Now the list page looks like this:

6. Pagination function

        Here we take the student list as an example and add the pagination query function. Note that other page list queries have been used in each key page. In order to avoid affecting other functions, it is recommended to create a new paging query function.

6.1 Paging function

        First open the src/utils/utils.js file and add the paging function, the code is as follows:

/**
 * 生成分页数据
 */
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 Add pagination query function

        Open db/model/student.js and add the pagination query function loadStudentPage(), the code is as follows:

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 interface

        Open api/index.js, add pagination query interface function, the code is as follows:

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

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

6.4 Add pagination code

In the html part, add the pagination code under the list, the code is as follows:

<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>

In the js part, introduce the getStudentPageList interface function, add paging parameters in data, and add paging switching events. The code is as follows:

 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 Modify list query function

        Since the total amount of data needs to be returned in the pagination query function, the structure of the original returned result has changed, so the updateList() function needs to be slightly adjusted. The code is as follows:

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);
      })
    },

    //...
}

At this time, the page effect is as follows:

        So far, the development of the system has been completed, and interested friends can upgrade and optimize it.

        Due to recent work reasons, it is not possible to spare time to develop every day, so some are not coherent, please forgive me. This article does not go into too much detail about additions, deletions, modifications, and checks, because they are all similar, and you can copy the code to run locally and do your own research.

Guess you like

Origin blog.csdn.net/jiciqiang/article/details/127463512