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

news/2024/4/28 11:58:05/文章来源:https://blog.csdn.net/jiciqiang/article/details/127463512

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

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

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

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

        

一、管理员列表

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

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

1.1 获取用户列表

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

/*** 获取用户列表*/
export const loadUserAllList = name => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName);//获取所有数据let alls = store.getAll();alls.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}alls.onsuccess = function(e){let result = e.target.result;if(result){let data = result.map(item => {delete item['password'];delete item['accesstoken'];return item;});//如果name值存在,则进行过滤if(name){data = data.filter(item => item.name.includes(name));}resolve(rJson(1, data, '获取成功~'))}else{reject(rJson(0, null, '未查询到数据~'))}// console.log('store', result);}});
}

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

import { loadUserAllList } from '@/db/model/user'/*** 获取用户列表*/
export const userAllList = keyword => {return loadUserAllList(keyword);
}

        html代码:

<template>
<div class="index-wrap"><el-breadcrumb separator-class="el-icon-arrow-right"><el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item><el-breadcrumb-item>管理员列表</el-breadcrumb-item></el-breadcrumb><br /><br /><!-- filter-wrap --><div class="filter-wrap"><div class="item left"><el-form :inline="true" class="demo-form-inline"><el-form-item label="账号"><el-input size="small" v-model="keyword" placeholder="请输入账号"></el-input></el-form-item><el-form-item><el-button size="small" type="primary" @click="updateUserList">查询</el-button></el-form-item></el-form></div><div class="item right"><el-form :inline="true" class="demo-form-inline"><el-form-item><el-button size="small" type="primary" @click="addUserEvent">新增</el-button><el-button size="small" type="danger" @click="deleteSelectedUser">删除</el-button></el-form-item></el-form></div></div><!-- /filter-wrap --><!-- table-wrap --><div class="table-wrap"><el-table:data="tableList"style="width: 100%"><el-table-column type="selection" label="选择" width="50" :selectable="selectableFunc"></el-table-column><el-table-column prop="name" label="账号"></el-table-column><el-table-column prop="phone" label="手机号"></el-table-column><el-table-column prop="createtime" label="创建日期"></el-table-column><el-table-column prop="updatetime" label="更新日期"></el-table-column><el-table-column label="操作" width="150"><template slot-scope="scope"><el-button type="primary" size="mini" icon="el-icon-edit" circle></el-button><el-button type="danger" size="mini" :disabled="userInfo.id==scope.row.id" icon="el-icon-delete" circle></el-button></template></el-table-column></el-table></div><!-- /table-wrap -->
</div>
</template>

        样式部分:

.index-wrap{padding: 20px;
}.filter-wrap{display: table;width: 100%;.item{display: table-cell;vertical-align: middle;&.left{text-align: left;}//left end&.right{text-align: right;}//right end}
}

        JS代码部分:

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

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

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

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

1.2 新增数据

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

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

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

代码如下:

/*** 增加 或 编辑用户信息*/
export const toggleUser = data => {return new Promise((resolve, reject) => {//打开游标let {store, index} = openTransactionIndex(storeName, 'name', CONST_READ.READWRITE);let res;//md5处理密码if(data['password']){data.password = hex_md5(data.password);}//用户ID存在,则为编辑if(data['id']&&data.id!=0){data['updatetime'] = new Date().getTime();//获取原数据res = store.get(data.id);res.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(e){let result = e.target.result;if(result){//合并数据,并保存res = store.put(Object.assign(result, data));res.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(){resolve(rJson(1, null, '保存成功~'))}}else{reject(rJson(0, e, '用户数据不存在~'));}}}//新增(需要判断用户名是否已存在)else{//通过索引 获取用户名,判断用户名是否已存在res = index.getKey(data.name);res.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(e){let result = e.target.result;//如果用户名已存在,返回错误信息if(result){reject(rJson(0, e, '该用户名已存在~'));}//用户名不存在,则直接添加else{data['createtime'] = new Date().getTime();data['updatetime'] = new Date().getTime();res = store.add(data);res.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(){resolve(rJson(1, null, '保存成功~'))}}//if 2 end}//索引 End}//if end});
}

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

import { toggleUser } from '@/db/model/user'/*** 添加用户信息*/
export const addUserInfo = param => {return toggleUser(param);
}

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

        弹框页面html代码部分:

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

        JS代码部分:

<script>import { getUserById, addUserInfo, editUserInfo } from '@/api'import { hex_md5 } from '@/utils/md5'export default {props: {//用户IDuid: {type: Number,default: () => 0},visible: {type: Boolean,default: () => false}},data(){var validateUsername = (rule, value, callback) => {if (value === '') {callback(new Error('请输入用户名'));} else {callback();}};var validatePhone = (rule, value, callback) => {if (value === '') {callback(new Error('请输入手机号'));} else if(!/^1[0-9]{10}$/.test(value)){callback(new Error('请输入正确的手机号'));} else {callback();}};var validatePass = (rule, value, callback) => {if(this.uid == 0){if (value === '') {callback(new Error('请输入密码'));} else if(value.length < 6){callback(new Error('密码不能小于6位'));} else {if (this.form.checkPass !== '') {this.$refs.ruleForm.validateField('checkPass');}callback();}}else if(this.form.password){if (value === '') {callback(new Error('请输入密码'));} else if(value.length < 6){callback(new Error('密码不能小于6位'));} else {if (this.form.checkPass !== '') {this.$refs.ruleForm.validateField('checkPass');}callback();}}else{callback();}};var validatePass2 = (rule, value, callback) => {if (value === '') {callback(new Error('请再次输入密码'));} else if (value !== this.form.password) {callback(new Error('两次输入密码不一致!'));} else {callback();}};var validateOldPwd = (rule, value, callback) => {if (value === '') {callback(new Error('请输入原密码'));} else if (hex_md5(value) !== this.oldPassword) {callback(new Error('密码错误!'));} else {callback();}};return {oldPassword: "",  //编辑时,记录旧密码form: {name: "",password: "",checkPass: "",phone: "",opwd: ""},formLabelWidth: '80px',rules: {name: [{ validator: validateUsername, trigger: 'blur' }],phone: [{ validator: validatePhone, trigger: 'blur' }],password: [{ validator: validatePass, trigger: 'blur' }],checkPass: [{ validator: validatePass2, trigger: 'blur' }],opwd: [{ validator: validateOldPwd, trigger: 'blur' }]}}},methods: {/*** 获取提交的数据* @date 2022/10/22*/getParam(){let data = {};if(this.form['name']){data['name'] = this.form.name;}if(this.form['password']){data['password'] = this.form.password;}if(this.form['phone']){data['phone'] = this.form.phone;}return data;},/*** 添加用户信息* @date 2022/10/22*/addUserInfo(){addUserInfo(this.getParam()).then(() => {this.$emit('saveSuccessChange', {});this.closeEvent();}).catch(e => {this.$message.error(e.msg);});},/*** 提交表单*/submitForm(){this.$refs['ruleForm'].validate((valid) => {if(valid){this.addUserInfo();}else{return false;}});},/*** 关闭事件*/closeEvent(){this.$refs['ruleForm'].resetFields();this.$emit('closeChange', {});},}}
</script>

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

import UserDailog from '@/components/UserDailog'export default {data () {return {//选择IDselectId: 0,//查询关键字keyword: "",/*** 是否显示弹框*/isShowDialog: false,/*** 列表数据*/tableList: [],/*** 选的项*/multipleSelection: []}},components: {UserDailog},//...methods: {/*** 关闭弹框*/closeChange(){this.isShowDialog = false;},/*** 新增用户信息*/addUserEvent(){this.selectId = 0;this.isShowDialog = true;},//...}
}

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

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

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

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

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

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

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

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

 

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

1.3 修改数据

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

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

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

/*** 通过ID获取用户信息*/
export const getUserInfoById = id => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName);//通过ID获取数据let data = store.get(id);data.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}data.onsuccess = function(e){let result = e.target.result;if(result){delete result['accesstoken'];resolve(rJson(1, result, '获取成功~'))}else{reject(rJson(0, e, '数据不存在~'));}}});
}

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

import { toggleUser, getUserInfoById } from '@/db/model/user'/*** 获取用户信息*/
export const getUserById = id => {return getUserInfoById(id);
}/*** 编辑用户信息*/
export const editUserInfo = param => {return toggleUser(param);
}

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

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

import { getUserById, addUserInfo, editUserInfo } from '@/api'
import { hex_md5 } from '@/utils/md5'export default {props: {//用户IDuid: {type: Number,default: () => 0},visible: {type: Boolean,default: () => false}},data(){var validateUsername = (rule, value, callback) => {if (value === '') {callback(new Error('请输入用户名'));} else {callback();}};var validatePhone = (rule, value, callback) => {if (value === '') {callback(new Error('请输入手机号'));} else if(!/^1[0-9]{10}$/.test(value)){callback(new Error('请输入正确的手机号'));} else {callback();}};var validatePass = (rule, value, callback) => {if(this.uid == 0){if (value === '') {callback(new Error('请输入密码'));} else if(value.length < 6){callback(new Error('密码不能小于6位'));} else {if (this.form.checkPass !== '') {this.$refs.ruleForm.validateField('checkPass');}callback();}}else if(this.form.password){if (value === '') {callback(new Error('请输入密码'));} else if(value.length < 6){callback(new Error('密码不能小于6位'));} else {if (this.form.checkPass !== '') {this.$refs.ruleForm.validateField('checkPass');}callback();}}else{callback();}};var validatePass2 = (rule, value, callback) => {if (value === '') {callback(new Error('请再次输入密码'));} else if (value !== this.form.password) {callback(new Error('两次输入密码不一致!'));} else {callback();}};var validateOldPwd = (rule, value, callback) => {if (value === '') {callback(new Error('请输入原密码'));} else if (hex_md5(value) !== this.oldPassword) {callback(new Error('密码错误!'));} else {callback();}};return {oldPassword: "",  //编辑时,记录旧密码form: {name: "",password: "",checkPass: "",phone: "",opwd: ""},formLabelWidth: '80px',rules: {name: [{ validator: validateUsername, trigger: 'blur' }],phone: [{ validator: validatePhone, trigger: 'blur' }],password: [{ validator: validatePass, trigger: 'blur' }],checkPass: [{ validator: validatePass2, trigger: 'blur' }],opwd: [{ validator: validateOldPwd, trigger: 'blur' }]}}},watch: {uid(){if(this.uid!=0){this.updateUserInfo();}}},methods: {/*** 获取用户信息*/updateUserInfo(){getUserById(this.uid).then(res => {if(res.code==1&&res['data']){this.form['name'] = res.data.name;this.form['phone'] = res.data.phone;this.oldPassword = res.data.password;}}).catch(e => {this.$message.error(e.msg);this.closeEvent();// console.error(e);})},/*** 获取提交的数据*/getParam(){let data = {};if(this.form['name']){data['name'] = this.form.name;}if(this.form['password']){data['password'] = this.form.password;}if(this.form['phone']){data['phone'] = this.form.phone;}return data;},/*** 添加用户信息*/addUserInfo(){addUserInfo(this.getParam()).then(() => {this.$emit('saveSuccessChange', {});this.closeEvent();}).catch(e => {this.$message.error(e.msg);});},/*** 编辑用户信息*/editUserInfo(){editUserInfo({id: this.uid,...this.getParam()}).then(() => {this.$emit('saveSuccessChange', {});this.closeEvent();}).catch(e => {this.$message.error(e.msg);});},/*** 提交表单*/submitForm(){this.$refs['ruleForm'].validate((valid) => {if(valid){//新增用户if(this.uid==0){this.addUserInfo();}//编辑用户else{this.editUserInfo();}}else{return false;}});},/*** 关闭事件*/closeEvent(){this.$refs['ruleForm'].resetFields();this.$emit('closeChange', {});},}}

        编辑界面如下图:

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

1.4 删除某条数据

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

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

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

import { deleteUserById } from '@/db/model/user'/*** 删除用户信息*/
export const deleteUserInfo = id => {return deleteUserById(id);
}

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

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

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

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

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

1.5 删除选中多条数据

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

/*** 通过ID删除多条用户信息*/
export const deleteUserByIds = ids => {return new Promise((resolve, reject) => {if(Array.isArray(ids)){//打开游标let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);//打开游标let cursor = store.openCursor();cursor.onerror = function(e){reject(rJson(0, e, '操作出错了~'));}cursor.onsuccess = function(e){let result = e.target.result;if(result){if(ids.includes(result.key)){result.delete();}result.continue();}else{resolve(rJson(1, null, '删除成功~'))}}}else{reject(rJson(0, e, '请传入数组形式ID数据~'));}//end});
}

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

import { deleteUserByIds } from '@/db/model/user'/*** 删除选择中项的用户信息*/
export const deleteUserChecked = ids => {return deleteUserByIds(ids);
}

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

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

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

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

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

二、年级管理

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

       2.1 数据库操作文件

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

import { DBIsLoadSuccess, openTransactionIndex, CONST_READ } from '@/db'
import { rJson } from '@/utils/utils'let storeName = 'grade';/*** 获取年级列表*/
export const loadGradeAllList = name => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName);//获取所有数据let alls = store.getAll();alls.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}alls.onsuccess = function(e){let result = e.target.result;if(result){let rData = result;if(name){rData = result.filter(item => item.name.includes(name));}resolve(rJson(1, rData, '获取成功~'))}else{reject(rJson(0, null, '未查询到数据~'))}// console.log('store', result);}});
}/*** 增加 或 编辑 年级信息*/
export const toggleGrade = data => {return new Promise((resolve, reject) => {//打开游标let {store, index} = openTransactionIndex(storeName, 'name', CONST_READ.READWRITE);let res;//用户ID存在,则为编辑if(data['id']&&data.id!=0){data['updatetime'] = new Date().getTime();//获取原数据res = store.get(data.id);res.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(e){let result = e.target.result;if(result){//合并数据,并保存res = store.put(Object.assign(result, data));res.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(){resolve(rJson(1, null, '保存成功~'))}}else{reject(rJson(0, e, '年级不存在~'));}}}//新增(需要判断用户名是否已存在)else{//通过索引 获取用户名,判断用户名是否已存在res = index.getKey(data.name);res.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(e){let result = e.target.result;//如果用户名已存在,返回错误信息if(result){reject(rJson(0, e, '该年级已存在~'));}//用户名不存在,则直接添加else{data['createtime'] = new Date().getTime();data['updatetime'] = new Date().getTime();res = store.add(data);res.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(){resolve(rJson(1, null, '保存成功~'))}}}}});
}/*** 通过ID删除 年级信息*/
export const deleteGradeById = id => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);//删除指定用户信息let res = store.delete(id);res.onerror = function(e){reject(rJson(0, e, '操作出错了~'));}res.onsuccess = function(){resolve(rJson(1, null, '删除成功~'))}});
}/*** 通过ID删除多条 年级信息*/
export const deleteGradeByIds = ids => {return new Promise((resolve, reject) => {if(Array.isArray(ids)){//打开游标let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);//打开游标let cursor = store.openCursor();cursor.onerror = function(e){reject(rJson(0, e, '操作出错了~'));}cursor.onsuccess = function(e){let result = e.target.result;if(result){if(ids.includes(result.key)){result.delete();}result.continue();}else{resolve(rJson(1, null, '删除成功~'))}}}else{reject(rJson(0, e, '请传入数组形式ID数据~'));}});
}

       2.2 api接口

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

import {loadGradeAllList,toggleGrade,deleteGradeById,deleteGradeByIds
} from '@/db/model/grade'/*** 获取年级列表*/
export const gradeAllList = keyword => {return loadGradeAllList(keyword);
}/*** 添加 或 修改指定年级信息*/
export const toggleGradeInfo = name => {return toggleGrade(name);
}/*** 删除指定年级*/
export const deleteGradeInfo = id => {return deleteGradeById(id);
}/*** 删除指定多项年级信息*/
export const deleteGradeChecked  = ids => {return deleteGradeByIds(ids);
}

       2.3 列表页面

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

        html代码部分:

<template>
<div class="index-wrap"><el-breadcrumb separator-class="el-icon-arrow-right"><el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item><el-breadcrumb-item>年级列表</el-breadcrumb-item></el-breadcrumb><br /><br /><div class="filter-wrap"><div class="item left"><el-form :inline="true" class="demo-form-inline"><el-form-item label="年级名称"><el-input size="small" v-model="keyword" placeholder="请输入年级名称"></el-input></el-form-item><el-form-item><el-button size="small" type="primary" @click="updateList">查询</el-button></el-form-item></el-form></div><div class="item right"><el-form :inline="true" class="demo-form-inline"><el-form-item><el-button size="small" type="primary" @click="addEvent">新增</el-button><el-button size="small" type="info" @click="deleteCheckedEvent">删除</el-button></el-form-item></el-form></div></div><div class="table-wrap"><el-table:data="tableList"@selection-change="selectionChange"style="width: 100%"><el-table-column type="selection" label="选择" width="50"> </el-table-column><el-table-column prop="name" label="年级名称"></el-table-column><el-table-column prop="createtime" label="创建日期"></el-table-column><el-table-column prop="updatetime" label="更新日期"></el-table-column><el-table-column label="操作" width="150"><template slot-scope="scope"><el-button type="primary" size="mini" icon="el-icon-edit" circle @click="editEvent(scope.row.id, scope.row.name)"></el-button><el-button type="danger" size="mini" icon="el-icon-delete" circle @click="deleteEvent(scope.row.id)"></el-button></template></el-table-column></el-table></div></div>
</template>

        样式部分:

.index-wrap{padding: 20px;
}.filter-wrap{display: table;width: 100%;.item{display: table-cell;vertical-align: middle;&.left{text-align: left;}&.right{text-align: right;}}
}

        JS部分:

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

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

列表页面:

新增页面:

三、教师列表

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

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

        3.1 数据库操作文件

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

import { DBIsLoadSuccess, openTransactionIndex, CONST_READ } from '@/db'
import { rJson } from '@/utils/utils'let storeName = 'teacher';/*** 获取 教师列表*/
export const loadTeacherAllList = name => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName);//获取所有数据let alls = store.getAll();alls.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}alls.onsuccess = function(e){let result = e.target.result;if(result){let rData = result;if(name){rData = result.filter(item => item.name.includes(name));}resolve(rJson(1, rData, '获取成功~'))}else{reject(rJson(0, null, '未查询到数据~'))}// console.log('store', result);}});
}/*** 获取教师信息*/
export const getTecharInfoById = id => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName);//通过ID获取数据let data = store.get(id);data.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}data.onsuccess = function(e){let result = e.target.result;if(result){resolve(rJson(1, result, '获取成功~'))}else{reject(rJson(0, e, '数据不存在~'));}}});
}/*** 增加 或 编辑 教师信息*/
export const toggleTeacher = data => {return new Promise((resolve, reject) => {//打开游标let {store, index} = openTransactionIndex(storeName, 'name', CONST_READ.READWRITE);let res;//ID存在,则为编辑if(data['id']&&data.id!=0){data['updatetime'] = new Date().getTime();//获取原数据res = store.get(data.id);res.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(e){let result = e.target.result;if(result){//合并数据,并保存res = store.put(Object.assign(result, data));res.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(){resolve(rJson(1, null, '保存成功~'))}}else{reject(rJson(0, e, '年级不存在~'));}}}//新增(需要判断是否已存在)else{//通过索引获取,判断是否已存在res = index.getKey(data.name);res.onerror = function(){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(e){let result = e.target.result;//如果已存在,返回错误信息if(result){reject(rJson(0, e, '该教师已存在~'));}//不存在,则直接添加else{data['createtime'] = new Date().getTime();data['updatetime'] = new Date().getTime();res = store.add(data);res.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(){resolve(rJson(1, null, '保存成功~'))}}//if 2 end}//索引 End}//if end});
}/*** 通过ID删除教师信息*/
export const deleteTeacherById = id => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);//删除指定信息let res = store.delete(id);res.onerror = function(e){reject(rJson(0, e, '操作出错了~'));}res.onsuccess = function(){resolve(rJson(1, null, '删除成功~'))}});
}/*** 通过ID删除多条教师信息*/
export const deleteTeacherByIds = ids => {return new Promise((resolve, reject) => {if(Array.isArray(ids)){//打开游标let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);//打开游标let cursor = store.openCursor();cursor.onerror = function(e){reject(rJson(0, e, '操作出错了~'));}cursor.onsuccess = function(e){let result = e.target.result;if(result){if(ids.includes(result.key)){result.delete();}result.continue();}else{resolve(rJson(1, null, '删除成功~'))}}}else{reject(rJson(0, e, '请传入数组形式ID数据~'));}});
}

        3.2 api接口

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

import {loadTeacherAllList,toggleTeacher,deleteTeacherById,deleteTeacherByIds,getTecharInfoById
} from '@/db/model/teacher'/*** 获取教师列表*/
export const getTeachersList = name => {return loadTeacherAllList(name);
}/*** 新增或修改教师信息*/
export const toggerTeacherInfo = params => {return toggleTeacher(params);
}/*** 通过ID获取教师信息*/
export const loadTeacherById = id => {return getTecharInfoById(id);
}/*** 单个教师信息删除*/
export const deleteTeacherInfo = id => {return deleteTeacherById(id);
}/*** 删除指定多个教师信息*/
export const deleteSelectedTeacherInfo = ids => {return deleteTeacherByIds(ids);
}

        3.3 新增页面

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

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

js部分代码:

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

添加界面如下:

        3.4 列表页面

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

<template>
<div class="index-wrap"><el-breadcrumb separator-class="el-icon-arrow-right"><el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item><el-breadcrumb-item>教师列表</el-breadcrumb-item></el-breadcrumb><br /><br /><div class="filter-wrap"><div class="item left"><el-form :inline="true" class="demo-form-inline"><el-form-item label="教师姓名"><el-input size="small" placeholder="请输入教师姓名" v-model="keyword"></el-input></el-form-item><el-form-item><el-button size="small" type="primary" @click="updateList">查询</el-button></el-form-item></el-form></div><div class="item right"><el-form :inline="true" class="form-inline"><el-form-item><el-button size="small" type="primary" @click="showAddDialog">新增</el-button><el-button size="small" type="info" @click="deleteSelectedTeacher">删除</el-button></el-form-item></el-form></div></div><div class="table-wrap"><el-table@selection-change="selectionChange":data="tableList"style="width: 100%"><el-table-column type="selection" label="选择" width="50"> </el-table-column><el-table-column prop="name" label="教师姓名"></el-table-column><el-table-column prop="registration" label="户籍"></el-table-column><el-table-column prop="address" label="居住地址"></el-table-column><el-table-column prop="age" label="年龄" width="80"><template slot-scope="scope"><span>{{scope.row.birthday | filterAge}}</span></template></el-table-column><el-table-column prop="createtime" label="创建日期" width="180"></el-table-column><el-table-column prop="updatetime" label="更新日期" width="180"></el-table-column><el-table-column label="操作" width="150"><template slot-scope="scope"><el-button type="primary" size="mini" icon="el-icon-edit" circle @click="editDialog(scope.row.id)"></el-button><el-button type="danger" size="mini" icon="el-icon-delete" circle @click="deleteTeacherEvent(scope.row.id)"></el-button></template></el-table-column></el-table></div><TeacherDialog :uid="selectId" :visible="isShowDialog" @closeChange="closeChange" @saveChange="saveChange"></TeacherDialog>
</div>
</template>

js部分代码:

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

列表界面如下:

四、班级管理

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

4.1 数据库操作文件

        db/model/classify.js代码:

import { DBIsLoadSuccess, openTransactionIndex, CONST_READ } from '@/db'
import { rJson } from '@/utils/utils'
import { getTeacherByIdsCursor } from './teacher.js'
import { getGradeByIdsCursor } from './grade.js'let storeName = 'classify';/*** 获取 班级信息*/
export const loadClassAllList = async (name) => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName);//获取所有数据let alls = store.getAll();alls.onerror = function(e){console.log('error', e)reject(rJson(0, e, '查询出错了~'));}alls.onsuccess = function(e){let result = e.target.result;if(result){let rData = result;if(name){rData = result.filter(item => item.name.includes(name));}resolve(rJson(1, rData, '获取成功~'))}else{reject(rJson(0, null, '未查询到数据~'))}// console.log('store', result);}});
}/*** 通过ID获取 班级信息*/
export const getClassInfoById = id => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName);//通过ID获取数据let data = store.get(id);data.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}data.onsuccess = function(e){let result = e.target.result;if(result){resolve(rJson(1, result, '获取成功~'))}else{reject(rJson(0, e, '数据不存在~'));}}});
}/*** 通过年级ID获取对应班级信息*/
export const getClassInfoByKey = key => {return new Promise((resolve, reject) => {//打开游标let {store, cursor} = openTransactionIndex(storeName, 'gid'),reData = [];cursor.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}cursor.onsuccess = function(e){let result = e.target.result;if(result){if(result.key==key){reData.push({id: result.value.id,name: result.value.name});}result.continue();}else{resolve(rJson(1, reData, '获取成功~'))// console.log('end')}}});
}/*** 增加 或 编辑 班级信息*/
export const toggleClass = data => {return new Promise((resolve, reject) => {//打开游标let {store, index} = openTransactionIndex(storeName, 'name', CONST_READ.READWRITE);let res;//ID存在,则为编辑if(data['id']&&data.id!=0){data['updatetime'] = new Date().getTime();//获取原数据res = store.get(data.id);res.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(e){let result = e.target.result;if(result){//合并数据,并保存res = store.put(Object.assign(result, data));res.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(){resolve(rJson(1, null, '保存成功~'))}}else{reject(rJson(0, e, '年级不存在~'));}}}//新增(需要判断是否已存在)else{//通过索引获取,判断是否已存在res = index.getKey(data.name);res.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(e){let result = e.target.result;//如果已存在,返回错误信息if(result){reject(rJson(0, e, '该年级已存在~'));}//不存在,则直接添加else{data['createtime'] = new Date().getTime();data['updatetime'] = new Date().getTime();res = store.add(data);res.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(){resolve(rJson(1, null, '保存成功~'))}}//if 2 end}//索引 End}//if end});
}/*** 通过ID删除班级*/
export const deleteClassById = id => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);//删除指定信息let res = store.delete(id);res.onerror = function(e){reject(rJson(0, e, '操作出错了~'));}res.onsuccess = function(){resolve(rJson(1, null, '删除成功~'))}});
}/*** 通过ID删除多条班级*/
export const deleteClassByIds = ids => {return new Promise((resolve, reject) => {if(Array.isArray(ids)){//打开游标let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);//打开游标let cursor = store.openCursor();cursor.onerror = function(e){reject(rJson(0, e, '操作出错了~'));}cursor.onsuccess = function(e){let result = e.target.result;if(result){if(ids.includes(result.key)){result.delete();}result.continue();}else{resolve(rJson(1, null, '删除成功~'))}}}else{reject(rJson(0, e, '请传入数组形式ID数据~'));}//end});
}

4.2 api接口

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

import {loadClassAllList,toggleClass,getClassInfoById,deleteClassById,deleteClassByIds,getClassInfoByKey
} from '@/db/model/classify'/*** 获取班级列表*/
export const getClassList = name => {return loadClassAllList(name);
}/*** 新增或保存 班级信息*/
export const toggleClassInfo = param => {return toggleClass(param);
}/*** 通过索引获取对应班级信息*/
export const getClassByKey = key => {return getClassInfoByKey(key);
}/*** 获取班级信息 通过ID*/
export const getClassifyById = id => {return getClassInfoById(id);
}/*** 通过ID删除指定班级信息*/
export const deleteClassInfoById = id => {return deleteClassById(id);
}/*** 通过选择中的ID删除 班级信息*/
export const deleteClassSelectedInfoByIds = ids => {return deleteClassByIds(ids);
}

4.3 新增班级页面

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

<template><el-dialog :title="uid!=0?'编辑':'新增'" :visible="visible" @close="closeEvent" width="420px" class="dialog-wrap"><el-form :model="form" :rules="rules"  status-icon ref="ruleForm"><el-form-item label="班级名称" :label-width="formLabelWidth" prop="name" required><el-input v-model="form.name" autocomplete="off" size="small"></el-input></el-form-item><el-form-item label="选择年级" :label-width="formLabelWidth" prop="grade" required><el-select  size="small" v-model="form.grade" placeholder="请选择"><el-optionv-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-optionv-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"borderstyle="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-optionv-for="item in masterOptions":key="item.id":label="item.name":value="item.id"></el-option></el-select></template></el-table-column></el-table></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button size="small" @click="closeEvent">取 消</el-button><el-button size="small" type="primary" @click="submitForm">保 存</el-button></div></el-dialog>
</template>

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

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

        js代码部分:

<script>import { gradeAllList, getTeachersList, toggleClassInfo, getClassifyById } from '@/api'export default {props: {//用户IDuid: {type: Number,default: () => 0},visible: {type: Boolean,default: () => false}},data(){return {formLabelWidth: '80px',gradeOptions: [],   //年级masterOptions: [],  //教师courseList: [{"name": "语文", "tid": ""},{"name": "数据", "tid": ""},{"name": "英文", "tid": ""},],form: {name: "",master: "",grade: ""},rules: {name: [{ required: true, message: '请输入班级名称', trigger: 'blur' },{ required: true, message: '请输入班级名称', trigger: 'change' },],grade: [{ required: true, message: '请选择年级', trigger: 'blur' },{ required: true, message: '请选择年级', trigger: 'change' },],master: [{ required: true, message: '请选择班主任', trigger: 'blur' },{ required: true, message: '请选择班主任', trigger: 'change' },],}}},watch: {uid(){if(this.uid!=0){this.updateClassInfo();}}},created() {this.updatePropsInfo();},methods: {/*** 获取班级信息*/updateClassInfo(){getClassifyById(this.uid).then(res => {if(res.code==1){this.form = {name: res.data.name,master: res.data.mid,grade: res.data.gid}if(Array.isArray(res.data['ts'])&&res.data.ts.length>0){this.courseList = res.data.ts;}}// console.log(res);}).catch(e => {console.error(e);})},/*** 获取属性信息*/updatePropsInfo(){Promise.all([gradeAllList(), getTeachersList()]).then(res => {let gradeList = res[0]['data'],teacherList = res[1]['data'];if(Array.isArray(gradeList)){this.gradeOptions = gradeList.map(item => item);}if(Array.isArray(teacherList)){this.masterOptions = teacherList;}}).catch(e => {console.error(e);})},/*** 添加班级信息*/addUserInfo(){let params = this.getParams();toggleClassInfo(params).then(res => {if(res.code==1){this.$message.success('保存成功');this.$emit('saveSuccessChange', {});}}).catch(e => {this.$message.success(e.msg);console.error(e);});},/*** 编辑班级信息*/editUserInfo(){let params = this.getParams();params['id'] = this.uid;toggleClassInfo(params).then(res => {if(res.code==1){this.$message.success('保存成功');this.$emit('saveSuccessChange', {});}}).catch(e => {this.$message.success(e.msg);console.error(e);});},/*** 获取保存参数*/getParams(){let { name, grade, master } = this.form;return {name,gid: grade,mid: master,ts: this.courseList}},/*** 提交表单*/submitForm(){this.$refs['ruleForm'].validate((valid) => {if(valid){//新增班级if(this.uid==0){this.addUserInfo();}//编辑班级else{this.editUserInfo();}}else{return false;}});},/*** 关闭事件*/closeEvent(){this.$refs['ruleForm'].resetFields();this.courseList = this.courseList.map(item => {item['tid'] = "";return item;})this.$emit('closeChange', {});},}}
</script>

新增界面如下:

        

4.4 班级列表页

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

<template>
<div class="index-wrap"><el-breadcrumb separator-class="el-icon-arrow-right"><el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item><el-breadcrumb-item>班级列表</el-breadcrumb-item></el-breadcrumb><br /><br /><div class="filter-wrap"><div class="item left"><el-form :inline="true" class="demo-form-inline"><el-form-item label="班级名称"><el-input size="small" placeholder="请输入班级名称" v-model="keyword"></el-input></el-form-item><el-form-item><el-button size="small" type="primary" @click="updateList">查询</el-button></el-form-item></el-form></div><div class="item right"><el-form :inline="true" class="demo-form-inline"><el-form-item><el-button size="small" type="primary" @click="showAddDialog">新增</el-button><el-button size="small" type="info" @click="deleteSelectedClass">删除</el-button></el-form-item></el-form></div></div><div class="table-wrap"><el-table@selection-change="selectionChange":data="tableList"style="width: 100%"><el-table-column type="selection" label="选择" width="50"> </el-table-column><el-table-column prop="name" label="班级名称"></el-table-column><el-table-column prop="master" label="班主任"></el-table-column><el-table-column prop="grade" label="年级"></el-table-column><el-table-column prop="createtime" label="创建日期"></el-table-column><el-table-column prop="updatetime" label="更新日期"></el-table-column><el-table-column prop="trs" label="授课教师" type="expand" width="100px"><template slot-scope="scope"><el-tablesize="small":show-header="false":data="scope.row.ts"style="width: 100%"><el-table-column prop="name" width="100px"></el-table-column><el-table-column prop="teacher"></el-table-column></el-table></template></el-table-column><el-table-column label="操作" width="150"><template slot-scope="scope"><el-button type="primary" size="mini" icon="el-icon-edit" circle @click="editClassEvent(scope.row.id)"></el-button><el-button type="danger" size="mini" icon="el-icon-delete" circle @click="deleteEvent(scope.row.id)"></el-button></template></el-table-column></el-table></div><ClassDialog :visible="isShowDialog" :uid="selectedId" @closeChange="closeChange" @saveSuccessChange="saveSuccessChange"></ClassDialog></div>
</template>

js部分代码:

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

列表界面如下:

4.5 查询关联数据 

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

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

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

/*** 通过游标获取对应数据集*/
export const getTeacherByIdsCursor = ids => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName);//通过ID获取数据let cursor = store.openCursor(),reData = {};cursor.onerror = function(e){reject();}cursor.onsuccess = function(e){let result = e.target.result;if(result){if(ids.includes(result.value.id)){reData[result.value.id] = result.value;}result.continue();}else{resolve(reData);}}//end});
}

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

/*** 通过游标获取对应数据集*/
export const getGradeByIdsCursor = ids => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName);//通过ID获取数据let cursor = store.openCursor(),reData = {};cursor.onerror = function(e){reject();}cursor.onsuccess = function(e){let result = e.target.result;if(result){if(ids.includes(result.value.id)){reData[result.value.id] = result.value;}result.continue();}else{resolve(reData);}}//end});
}

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

/*** 获取 班级信息*/
export const loadClassAllList = async (name) => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName);//获取所有数据let alls = store.getAll();alls.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}alls.onsuccess = function(e){let result = e.target.result;if(result){let rData = result;if(name){rData = result.filter(item => item.name.includes(name));}let teacherIds = [];//拿到不重复的教师IDrData.forEach(item => {if(!teacherIds.includes(item.mid)){teacherIds.push(item.mid);}if(Array.isArray(item['ts'])&&item.ts.length>0){item.ts.forEach(sub => {if(!teacherIds.includes(sub.tid)){teacherIds.push(sub.tid);}});}})//查询关联数据Promise.all([getTeacherByIdsCursor(teacherIds), getGradeByIdsCursor(rData.map(item => item.gid))]).then(res => {let teacher = res[0],grade = res[1];//重组数据rData = rData.map(item => {if('undefined'!==typeof teacher[item.mid]){item['master'] = teacher[item.mid]['name'];}if('undefined'!==typeof grade[item.gid]){item['grade'] = grade[item.gid]['name'];}//查询到授课教师信息if(Array.isArray(item['ts'])&&item.ts.length>0){item.ts = item.ts.map(sub => {if('undefined'!==typeof teacher[sub.tid]){sub['teacher'] = teacher[sub.tid]['name'];}return sub;})}return item;});resolve(rJson(1, rData, '获取成功~'))}).catch(e => {reject(rJson(0, null, '关联数据查询错误~'))});}else{reject(rJson(0, null, '未查询到数据~'))}}});
}

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

五、学员列表

5.1 数据库操作文件

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

import { DBIsLoadSuccess, openTransactionIndex, CONST_READ } from '@/db'
import { rJson } from '@/utils/utils'
import { getClassByIdsCursor } from './classify.js'let storeName = 'student';/*** 获取 学员列表*/
export const loadStudentAllList = name => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName);//获取所有数据let alls = store.getAll();alls.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}alls.onsuccess = function(e){let result = e.target.result;if(result){let rData = result;if(name){rData = result.filter(item => item.name.includes(name));}resolve(rJson(1, rData, '获取成功~'))}else{reject(rJson(0, null, '未查询到数据~'))}// console.log('store', result);}});
}/*** 获取学员信息*/
export const getStudentInfoById = id => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName);//通过ID获取数据let data = store.get(id);data.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}data.onsuccess = function(e){let result = e.target.result;if(result){resolve(rJson(1, result, '获取成功~'))}else{reject(rJson(0, e, '数据不存在~'));}}});
}/*** 增加 或 编辑 员学信息*/
export const toggleStudent = data => {return new Promise((resolve, reject) => {//打开游标let {store, index} = openTransactionIndex(storeName, 'name', CONST_READ.READWRITE);let res;//ID存在,则为编辑if(data['id']&&data.id!=0){data['updatetime'] = new Date().getTime();//获取原数据res = store.get(data.id);res.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(e){let result = e.target.result;if(result){//合并数据,并保存res = store.put(Object.assign(result, data));res.onerror = function(){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(){resolve(rJson(1, null, '保存成功~'))}}else{reject(rJson(0, e, '年级不存在~'));}}}//新增(需要判断是否已存在)else{//通过索引获取,判断是否已存在res = index.getKey(data.name);res.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(e){let result = e.target.result;//如果用已存在,返回错误信息if(result){reject(rJson(0, e, '该学员已存在~'));}//不存在,则直接添加else{data['createtime'] = new Date().getTime();data['updatetime'] = new Date().getTime();res = store.add(data);res.onerror = function(){reject(rJson(0, e, '查询出错了~'));}res.onsuccess = function(){resolve(rJson(1, null, '保存成功~'))}}//if 2 end}//索引 End}//if end});
}/*** 通过ID删除学员信息*/
export const deleteStudentById = id => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);//删除指定信息let res = store.delete(id);res.onerror = function(e){reject(rJson(0, e, '操作出错了~'));}res.onsuccess = function(){resolve(rJson(1, null, '删除成功~'))}});
}/*** 通过ID删除多条学员信息*/
export const deleteStudentByIds = ids => {return new Promise((resolve, reject) => {if(Array.isArray(ids)){//打开游标let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);//打开游标let cursor = store.openCursor();cursor.onerror = function(e){reject(rJson(0, e, '操作出错了~'));}cursor.onsuccess = function(e){let result = e.target.result;if(result){if(ids.includes(result.key)){result.delete();}result.continue();}else{resolve(rJson(1, null, '删除成功~'))}}}else{reject(rJson(0, e, '请传入数组形式ID数据~'));}//end});
}

5.2 api接口

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

import {loadStudentAllList,toggleStudent,getStudentInfoById,deleteStudentById,deleteStudentByIds
} from '@/db/model/student'/*** 获取学员列表数据*/
export const getStudentList = name => {return loadStudentAllList(name);
}/*** 通过ID获取学员信息*/
export const loadStudentById = id => {return getStudentInfoById(id);
}/*** 添加 或 修改学员数据*/
export const toggleStudentInfo = params => {return toggleStudent(params);
}/*** 通过ID删除指定学员信息*/
export const deleteStudentInfoById = id => {return deleteStudentById(id);
}/*** 删除选中的学员信息*/
export const deleteStudentInfoByIds = ids => {return deleteStudentByIds(ids);
}

5.3 新增页面

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

<template><el-dialog :title="uid!=0?'编辑':'新增'" :visible="visible" @close="closeEvent" width="420px" class="dialog-wrap"><el-form :model="form" :rules="rules"  status-icon ref="ruleForm"><el-form-item label="学员姓名" :label-width="formLabelWidth" required prop="name"><el-input v-model="form.name" autocomplete="off" size="small"></el-input></el-form-item><el-form-item label="户籍" :label-width="formLabelWidth" required prop="registration"><el-input v-model="form.registration" autocomplete="off" size="small"></el-input></el-form-item><el-form-item label="手机号" :label-width="formLabelWidth" required prop="phone"><el-input v-model="form.phone" autocomplete="off" size="small"></el-input></el-form-item><el-form-item label="年级" :label-width="formLabelWidth" prop="gid"><el-select v-model="form.gid" placeholder="请选择" @change="gradeChange"><el-optionv-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-optionv-for="item in classOptions":key="item.value":label="item.label":value="item.value"></el-option></el-select></el-form-item><el-form-item label="居住地址" :label-width="formLabelWidth" required prop="address"><el-input v-model="form.address" autocomplete="off" size="small"></el-input></el-form-item><el-form-item label="出生日期" :label-width="formLabelWidth" required prop="birthday"><el-date-picker v-model="form.birthday" value-format="yyyy-MM-dd" type="date" placeholder="选择日期"></el-date-picker></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button size="small" @click="closeEvent">取 消</el-button><el-button size="small" type="primary" @click="submitForm">保 存</el-button></div></el-dialog>
</template>

js代码如下:

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

界面如下:

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

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

5.4 列表页面

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

<template>
<div class="index-wrap"><el-breadcrumb separator-class="el-icon-arrow-right"><el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item><el-breadcrumb-item>学员列表</el-breadcrumb-item></el-breadcrumb><br /><br /><div class="filter-wrap"><div class="item left"><el-form :inline="true" class="demo-form-inline"><el-form-item label="学员姓名"><el-input size="small" placeholder="请输入学员姓名" v-model="keyword"></el-input></el-form-item><el-form-item><el-button size="small" type="primary" @click="updateList">查询</el-button></el-form-item></el-form></div><div class="item right"><el-form :inline="true" class="demo-form-inline"><el-form-item><el-button size="small" type="primary" @click="showAddDialog">新增</el-button><el-button size="small" type="info" @click="deleteSelectedStudent">删除</el-button></el-form-item></el-form></div></div><div class="table-wrap"><el-table@selection-change="selectionChange":data="tableList"style="width: 100%"><el-table-column type="selection" label="选择" width="50"> </el-table-column><el-table-column prop="name" label="学员姓名"></el-table-column><el-table-column prop="registration" label="户籍"></el-table-column><el-table-column prop="address" label="居住地址"></el-table-column><el-table-column prop="classify" label="班级"></el-table-column><el-table-column prop="age" label="年龄" width="80"><template slot-scope="scope"><span>{{scope.row.birthday | filterAge}}</span></template></el-table-column><el-table-column prop="createtime" label="创建日期" width="160"></el-table-column><el-table-column prop="updatetime" label="更新日期" width="160"></el-table-column><el-table-column label="操作" width="150"><template slot-scope="scope"><el-button type="primary" size="mini" icon="el-icon-edit" circle @click="editEvent(scope.row.id)"></el-button><el-button type="danger" size="mini" icon="el-icon-delete" circle @click="deleteEvent(scope.row.id)"></el-button></template></el-table-column></el-table></div><StudentDialog :visible="isShowDialog" :uid="selectId" @closeChange="closeDialog" @saveChange="saveChange"></StudentDialog>
</div>
</template>

js代码部分:

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

界面效果如下:

5.5 关联数据查询

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

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

/*** 通过游标获取对应数据集*/
export const getClassByIdsCursor = ids => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName);//通过ID获取数据let cursor = store.openCursor(),reData = {};cursor.onerror = function(e){reject();}cursor.onsuccess = function(e){let result = e.target.result;if(result){if(ids.includes(result.value.id)){reData[result.value.id] = result.value;}result.continue();}else{resolve(reData);}}//end});
}

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

/*** 获取 学员列表*/
export const loadStudentAllList = name => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName);//获取所有数据let alls = store.getAll();alls.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}alls.onsuccess = function(e){let result = e.target.result;if(result){let rData = result;if(name){rData = result.filter(item => item.name.includes(name));}getClassByIdsCursor(rData.filter(item => item.cid).map(item => item.cid)).then(res => {rData = rData.map(item => {if('undefined'!==typeof res[item.cid]){item['classify'] = res[item.cid]['name'];}return item;})resolve(rJson(1, rData, '获取成功~'))}).catch(e => {reject(rJson(0, e, '查询出错了~'))});}else{reject(rJson(0, null, '未查询到数据~'))}}});
}

现在列表页面效果如下:

 

六、分页功能

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

6.1 分页功能函数

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

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

6.2 增加分页查询功能

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

import { DBIsLoadSuccess, openTransactionIndex, CONST_READ } from '@/db'
import { rJson, genderPage } from '@/utils/utils'
import { getClassByIdsCursor } from './classify.js'let storeName = 'student';/*** 获取 学员列表 - 分页模式* @param name 查询关键词* @param param 分页参数*/
export const loadStudentPage = (name, param) => {return new Promise((resolve, reject) => {//打开游标let {store} = openTransactionIndex(storeName);//获取所有数据let alls = store.getAll();alls.onerror = function(e){reject(rJson(0, e, '查询出错了~'));}alls.onsuccess = function(e){let result = e.target.result;if(result){let rData = result;if(name){rData = result.filter(item => item.name.includes(name));}//查询班级关联数据getClassByIdsCursor(rData.filter(item => item.cid).map(item => item.cid)).then(res => {rData = rData.map(item => {if('undefined'!==typeof res[item.cid]){item['classify'] = res[item.cid]['name'];}return item;})//通过genderPageData函数进行分页处理resolve(rJson(1, {list: genderPage(rData, param),total: rData.length}, '获取成功~'))}).catch(e => {reject(rJson(0, e, '查询出错了~'))});}else{reject(rJson(0, null, '未查询到数据~'))}}});
}

6.3 api接口

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

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

6.4 添加分页代码

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

<div class="table-wrap">...<el-paginationbackgroundlayout="prev, pager, next"@current-change="currentChange":current-page="page":page-size="pageSize":total="pageTotal"></el-pagination></div>

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

 import StudentDialog from '@/components/StudentDialog'import { getStudentList, getStudentPageList, deleteStudentInfoById, deleteStudentInfoByIds } from '@/api'import { formatDate } from '@/utils/utils'export default {data () {return {//...//分页参数page: 1,pageSize: 5,pageTotal: 0}},filters: {filterAge(val){let current = new Date(),bDate = new Date(val);return current.getFullYear() - bDate.getFullYear();}},components: {StudentDialog},created() {this.updateList();},methods: {/*** 当前页发生改变*/currentChange(page){this.page = page;this.updateList();}}

6.5 修改列表查询函数

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

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

此时页面效果如下:

        到此为止,该系统开发则已经完结了,有兴趣的朋友可以再升级和优化下。由于近期工作原因,不是每天都能抽出时间开发,所以有些地方可能不太连贯,望见谅。有问题,欢迎指出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_411635.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用VMware16克隆功能快速准备CentOS 7.9操作系统集群

记录&#xff1a;305 场景&#xff1a;使用VMware16克隆功能快速准备CentOS 7.9操作系统集群&#xff0c;主要内容&#xff1a;VMware16克隆功能功能使用、CentOS 7.9操作系统常用指令使用、制作本地yum源、安装JDK、配置集群NTP时间同步等。 版本&#xff1a; 虚拟机工具&a…

数据结构-难点突破(C++/Java详解实现串匹配算法KMP,next数组求法,KMP算法优化nextval数组)

文章目录1. 暴力匹配算法BF2. KMP算法next数组求法Java代码&#xff1a;C代码&#xff1a;KMP算法优化nextval数组1. 暴力匹配算法BF 在了解KMP算法前&#xff0c;就必须介绍串的暴力匹配算法&#xff08;BF算法&#xff09; BF算法&#xff0c;即暴力(Brute Force)算法&…

大赛征集令|首届“万应杯”低代码应用开发大赛报名开启啦!

探索&#xff0c;寻觅低码边界。 创新&#xff0c;做成未曾有人做过的事。 首届“万应杯”低代码应用开发大赛 报名正式启动啦&#xff01; 万元现金奖杯/证书项目转售收益 丰厚奖励&#xff0c;邀你来战&#xff01; 大赛时间 低码掘金&#xff0c;就在此时&#xff01; …

MySQL高级SQL语句(一)

MySQL高级SQL语句&#xff08;一&#xff09;MySQL高级SQL语句&#xff08;一&#xff09;一、高级SQL语句&#xff08;进阶查询&#xff09;1.1 select1.2 distinct1.3 where1.4 and 、or1.5 in1.6 between1.7 通配符1.8 like1.9 order by二、函数2.1 数学函数2.2 聚合函数2.3…

MSDC 4.3 接口规范(26)

MSDC 4.3 接口规范&#xff08;26&#xff09;7.4 组呼业务管理7.4.1 服务状态7.4.2 启动组呼业务7.4.2.1 接口函数7.4.2.2 先决条件7.4.2.3 说明7.4.2.4 调用流程7.4.2.4.1 启动组呼业务7.4.2.4.2 无法启动服务7.4.3 停止组呼服务7.4.3.1 接口函数7.4.3.2 先决条件7.4.3.3 说明…

SH-SSS丨《端到端音视频说话人日志网络》论文线上分享

SH Symposium Series on Speech (SH SSS 2022) SH SSS 是由语音之家打造的AI语音技术相关的前沿论文成果分享平台。 来自AI语音技术领域的优秀论文作者、专家学者&#xff0c;用最精炼的表达来解读最新的高质量论文。 分享的论文成果来自国内外顶级会议收录的优秀文章、前沿…

系统kafka不消费-topic问题

测试告诉说kafka的topic列表里面新加入了一个topic&#xff0c;然后就不消费数据了&#xff1b; 自己验证了一下&#xff0c;确实这样&#xff0c;如果去掉新的topic&#xff0c;数据就可以正常消费&#xff1b; 然后我查看定义发现&#xff0c;topicA是1个分区&#xff1b; …

段页式内存管理

文章目录分页、分段的优缺点分析段页式管理分段分页段页式管理的逻辑地址结构段页式存储的段表、页表的地址变换分页、分段的优缺点分析 分页管理它的缺点就是不方便按照逻辑块实现信息的共享和保护而分段管理&#xff0c;如果段长过大&#xff0c;为其分配很大的连续空间会很不…

WebDAV之葫芦儿·派盘+纸间书摘

纸间书摘 支持webdav方式连接葫芦儿派盘。 是专为喜欢做读书笔记的小伙伴量身打造的专属书摘app,不仅仅可以从别的app中导入图书,并且还能来帮助你选择性复制可以来轻松的搞定哦 所有功能完全免费,没有广告,不限制识别次数。 多种备份,本地备份和基于WebDAV协议的云端…

python基于PHP+MySQL的药店药品进销存管理系统

随着科技的发展,针对不同疾病的药品越来越多,不同的药品有不同的属性,用法用量等内容,如何让药店和医药公司更好的对药品进行管理,是很多人都在研究的问题,本系统就是在这样的一个基础上开发出来的 PHP药店药品进销存管理系统通过PHp&#xff1a;MySQL进行开发,主要完成了药店基…

狂神说java基础——面向对象编程

面向对象编程(oop) 1、什么是面向对象(00)面向过程:线性思维 面向对象:分类思维​ 本质:以类的方式组织代码,以对象的形式阻止(封装)数据三大特性:封装,继承,多态2、回顾方法的定义 方法的定义修饰符 返回值类型/** 修饰符 返回值类型 方法名(...){* 方法体* re…

Dropzone V4.5.1 for Mac 文件拖拽工具使用教程

简介 Dropzone 是一款Mac上的文件拖拽操作增强工具&#xff0c;这款软件可以让我们把大部分工作都通过拖拽来完成&#xff0c;比如保存文本、发送邮件、FTP上传、打开应用等等&#xff0c;只需要将文件拖拽到菜单栏上的窗口中即可&#xff0c;并且我们完全可以定制化这些操作&a…

移动测试Appium安装

移动测试Appium安装 一、环境搭建 1.Java sdk安装 并配置JAVA_HOME和PATH 2.Android SDK安装 &#xff08;1&#xff09;解压 &#xff08;2&#xff09;配置ANDROID_HOME和PATH 见教程&#xff1a;AndroidSDK下载及安装 Android SDK 下载安装及配置 3.虚拟机安装 这里下载的…

UnityShader34:非真实感水体渲染

一、水体渲染方案 1.1 水体动画 既然是动画&#xff0c;必然推导公式会和时间相关联&#xff0c;如果不追求表现&#xff0c;可以使用最无脑的 sin 函数&#xff1a; 其中 y 值 振幅*sin(频率*(x值-相对偏移))&#xff0c;感觉目前手机端非真实感渲染的话感觉这一套就够了&a…

Centos下部署CodiMD

Centos下部署CodiMD安装docker安装docker-compose安装git部署CodiMDCodiMD是HackMD的自由软件版本&#xff0c;由HackMD团队开发并开源&#xff0c;具有简化功能&#xff08;无需书本模式&#xff09;&#xff0c;您可以在社区中使用CodiMD&#xff0c;并拥有所有数据。支持浏览…

数据可视化之对外经济发展,近五年我国对外货物进出口总额持续上涨

哈喽&#xff0c;大家好&#xff0c;2021年在疫情仍在冲击全球经济之际&#xff0c;我国不论是在贸易规模方面&#xff0c;还是在国际市场份额方面皆取得进展。 下面是小编对国家统计局最新发布的报告进行报表数据处理分析后得到的数据可视化图表&#xff0c;展示了2021年我国对…

齐活了,Grafana 发布大规模持续性能分析开源数据库 - Phlare

Grafana Phlare 是一个用于聚合 continuous profiling(持续分析)数据的开源软件项目。Grafana Phlare 可以和 Grafana 完全集成&#xff0c;允许你与其他可观察信号相关联。 什么是 continuous profiling? 这个概念很有价值&#xff1a;Profiling 可以帮助你了解程序的资源使…

正规现货黄金中的MACD技术

MACD是整个现货黄金交易平台上面最受投资者欢迎的技术指标&#xff0c;所以我们这次来谈谈&#xff0c;这个全球使用率最高的技术分析指标。 MACD 的全名为 Moving Average Convergence / Divergence &#xff0c;它是一种移动平均线的波动指标&#xff0c;不过它使用的不是普通…

mysql数据库中的插入数据insert,中文字符集配置

目录 关键字insert 常见错误类型 指定一列插入数据 多列同时插入 插入效率问题 全列查询select * 查看数据库字符集类型&#xff1a; 更改数据库字符集 C&#xff1a;create 新增D&#xff1a;update 修改R&#xff1a;retrieve 查询D&#xff1a;delete 删除进行增删查…

Redis客户端RedisTemplate入门学习

Redis的Java客户端 Jedis客户端入门 1.引入依赖 <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.7.0</version></dependency>2.建立连接并操作 //建立连接BeforeEachvoid setUp()…