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);})},//...
}
此时页面效果如下:
到此为止,该系统开发则已经完结了,有兴趣的朋友可以再升级和优化下。由于近期工作原因,不是每天都能抽出时间开发,所以有些地方可能不太连贯,望见谅。有问题,欢迎指出。