IndexedDB是浏览器提供的本地数据库,它可以被网页脚本创建和操作。IndexedDB允许存储大量数据,提供查找接口,还能建立索引。这些都是LocalStorage或Cookie不具备的。就数据库类型而言,IndexedDB不属于关系型数据库(不支持SQL查询语句),更接近NoSQL数据库。
通过上一篇“本地数据库IndexedDB - 学员管理系统之登录(一)”,我们已完成了系统的登录功能,这一章节则完成相关列表管理功能,实现管理员列表、年级管理、班级管理、教师列表、学员列表等栏目的增删改查。
由于这中间工作较忙,离下篇发布时间相隔较长,并且结合后期开发过程,对前期部分定义内容进行了修改,有些地方差异,大家可以重新翻看上一篇。
上篇地址:本地数据库IndexedDB - 学员管理系统之登录(一)_觉醒法师的博客-CSDN博客
一、管理员列表
在开始前,我们将上一章节的用户登录信息再修复一下;当用户登录成功后,会将信息缓存到localStorage中,本地状态管理器中也会只在一份;用户列表管理时,遇到登录用户信息,需要判断是否可以修改或删除等,需要从store中获取用户信息,但是页面刷新后,store状态中的用户信息会丢失,这时我们在校验Token有效情况下,需要重新将缓存中的用户信息,保存到store状态中。打开store/actions.js文件,添加以下代码:
import Vue from 'vue'
import { USERINFO, TOKEN } from './mutationsType'
import { tokenIsFailure } from '@/api'
const actions = {
/**
* 重新加载缓存中用户信息
*/
reloadUserInfo({commit}){
let token = Vue.ls.get(TOKEN),
userInfo = Vue.ls.get(USERINFO);
if(token) {
commit(TOKEN, token);
}
if(userInfo) {
commit(USERINFO, userInfo);
}
},
//...
}
1.1 获取用户列表
首先我们在db/model/user.js中,定义loadUserAllList用户加载所有用户信息;筛选用户功能可通过传入name进行筛选,获取所有数据时通过filter进行过滤下即可;另外这里我们先使用getAll()方法来获取所有数据,在后期中我们会讲解如何进行分页查询。代码如下:
/**
* 获取用户列表
*/
export const loadUserAllList = name => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName);
//获取所有数据
let alls = store.getAll();
alls.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
alls.onsuccess = function(e){
let result = e.target.result;
if(result){
let data = result.map(item => {
delete item['password'];
delete item['accesstoken'];
return item;
});
//如果name值存在,则进行过滤
if(name){
data = data.filter(item => item.name.includes(name));
}
resolve(
rJson(1, data, '获取成功~')
)
}else{
reject(
rJson(0, null, '未查询到数据~')
)
}
// console.log('store', result);
}
});
}
第二步,在api/index.js中定义userAllList接口函数,代码如下:
import { loadUserAllList } from '@/db/model/user'
/**
* 获取用户列表
*/
export const userAllList = keyword => {
return loadUserAllList(keyword);
}
html代码:
<template>
<div class="index-wrap">
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>管理员列表</el-breadcrumb-item>
</el-breadcrumb>
<br /><br />
<!-- filter-wrap -->
<div class="filter-wrap">
<div class="item left">
<el-form :inline="true" class="demo-form-inline">
<el-form-item label="账号">
<el-input size="small" v-model="keyword" placeholder="请输入账号"></el-input>
</el-form-item>
<el-form-item>
<el-button size="small" type="primary" @click="updateUserList">查询</el-button>
</el-form-item>
</el-form>
</div>
<div class="item right">
<el-form :inline="true" class="demo-form-inline">
<el-form-item>
<el-button size="small" type="primary" @click="addUserEvent">新增</el-button>
<el-button size="small" type="danger" @click="deleteSelectedUser">删除</el-button>
</el-form-item>
</el-form>
</div>
</div>
<!-- /filter-wrap -->
<!-- table-wrap -->
<div class="table-wrap">
<el-table
:data="tableList"
style="width: 100%">
<el-table-column type="selection" label="选择" width="50" :selectable="selectableFunc"></el-table-column>
<el-table-column prop="name" label="账号"></el-table-column>
<el-table-column prop="phone" label="手机号"></el-table-column>
<el-table-column prop="createtime" label="创建日期"></el-table-column>
<el-table-column prop="updatetime" label="更新日期"></el-table-column>
<el-table-column label="操作" width="150">
<template slot-scope="scope">
<el-button type="primary" size="mini" icon="el-icon-edit" circle></el-button>
<el-button type="danger" size="mini" :disabled="userInfo.id==scope.row.id" icon="el-icon-delete" circle></el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- /table-wrap -->
</div>
</template>
样式部分:
.index-wrap{
padding: 20px;
}
.filter-wrap{
display: table;
width: 100%;
.item{
display: table-cell;
vertical-align: middle;
&.left{
text-align: left;
}
//left end
&.right{
text-align: right;
}
//right end
}
}
JS代码部分:
<script>
import { userAllList } from '@/api'
import { formatDate } from '@/utils/utils'
import { mapGetters } from 'vuex'
export default {
data () {
return {
//选择ID
selectId: 0,
//查询关键字
keyword: "",
/**
* 是否显示弹框
*/
isShowDialog: false,
/**
* 列表数据
*/
tableList: [],
/**
* 选的项
*/
multipleSelection: []
}
},
computed: {
...mapGetters(['userInfo'])
},
created() {
this.updateUserList();
},
methods: {
/**
* 禁用当前登录用户的删除判断
* @param {Object} row
* @param {Object} index
*/
selectableFunc(row, index){
return row.id!=this.userInfo.id;
},
/**
* 获取用户列表数据
*/
updateUserList(){
userAllList(this.keyword).then(res => {
if(res.code==1&&Array.isArray(res['data'])){
this.tableList = res.data.map(item => {
item['createtime'] = formatDate(item.createtime);
item['updatetime'] = formatDate(item.updatetime);
return item;
});
}
// console.log(res);
}).catch(e => {
this.tableList = [];
console.log('e', e);
});
//ajax end
}
}
}
</script>
以上准备工作做完后,我们页面就有用户数据了,如下图:
大家可以观察到admin的多选项 和 删除 按钮都是禁用的,这里因为当前登录用户是无法删除自己的。如何实现的呢,删除按钮是通过store中取到的用户ID和列表渲染用户ID进行对比,判断为当前登录用户则禁用;多选功能则是通过selectable功能,与store中的用户ID进行对比来判断的。
当然,现在列表数据是显示了,但是只有一条数据,无法通过条件进行筛选,这块等我们将新增功能完成后,再来操作。
1.2 新增数据
首先,我们在db/model/user.js中定义toggleUser函数,用于新增 或 编辑用户信息;当数据为新增时,先判断用户名是否已存在,如已存在返回错误信息,不存在直接新增为新用户;当数据为编辑时,先获取该用户原始数据,用原始数据和新数据进行合并,如果使用put保存,会覆盖掉之前未修改数据。
当编辑时候,先通过get()方法获取该用户所有信息,再合并数据。
当新增时候,先通过name索引判断该用户是否存在,存在则返回提示信息;不存在则直接添加。
代码如下:
/**
* 增加 或 编辑用户信息
*/
export const toggleUser = data => {
return new Promise((resolve, reject) => {
//打开游标
let {store, index} = openTransactionIndex(storeName, 'name', CONST_READ.READWRITE);
let res;
//md5处理密码
if(data['password']){
data.password = hex_md5(data.password);
}
//用户ID存在,则为编辑
if(data['id']&&data.id!=0){
data['updatetime'] = new Date().getTime();
//获取原数据
res = store.get(data.id);
res.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(e){
let result = e.target.result;
if(result){
//合并数据,并保存
res = store.put(Object.assign(result, data));
res.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(){
resolve(
rJson(1, null, '保存成功~')
)
}
}else{
reject(
rJson(0, e, '用户数据不存在~')
);
}
}
}
//新增(需要判断用户名是否已存在)
else{
//通过索引 获取用户名,判断用户名是否已存在
res = index.getKey(data.name);
res.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(e){
let result = e.target.result;
//如果用户名已存在,返回错误信息
if(result){
reject(
rJson(0, e, '该用户名已存在~')
);
}
//用户名不存在,则直接添加
else{
data['createtime'] = new Date().getTime();
data['updatetime'] = new Date().getTime();
res = store.add(data);
res.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(){
resolve(
rJson(1, null, '保存成功~')
)
}
}
//if 2 end
}
//索引 End
}
//if end
});
}
api/index.js添加addUserInfo()方法,代码如下:
import { toggleUser } from '@/db/model/user'
/**
* 添加用户信息
*/
export const addUserInfo = param => {
return toggleUser(param);
}
接下来,我们来创建新增弹框组件,在components目录中创建UserDailog目录,再新增index.vue。
弹框页面html代码部分:
<template>
<el-dialog :title="uid!=0?'编辑':'新增'" :visible="visible" @close="closeEvent" width="420px" class="dialog-wrap">
<el-form :model="form" :rules="rules" status-icon ref="ruleForm">
<el-form-item label="用户名" :label-width="formLabelWidth" prop="name">
<el-input v-model="form.name" autocomplete="off" size="small"></el-input>
</el-form-item>
<el-form-item v-if="uid!=0" label="原密码" :label-width="formLabelWidth" prop="opwd">
<el-input v-model="form.opwd" type="password" autocomplete="off" size="small"></el-input>
</el-form-item>
<el-form-item label="密码" :label-width="formLabelWidth" prop="password">
<el-input v-model="form.password" type="password" autocomplete="off" size="small"></el-input>
</el-form-item>
<el-form-item v-if="uid==0||(uid!=0&&form.password)" label="确认密码" :label-width="formLabelWidth" prop="checkPass">
<el-input v-model="form.checkPass" type="password" autocomplete="off" size="small"></el-input>
</el-form-item>
<el-form-item label="手机号" :label-width="formLabelWidth" prop="phone">
<el-input v-model="form.phone" autocomplete="off" size="small"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button size="small" @click="closeEvent">取 消</el-button>
<el-button size="small" type="primary" @click="submitForm">保 存</el-button>
</div>
</el-dialog>
</template>
JS代码部分:
<script>
import { getUserById, addUserInfo, editUserInfo } from '@/api'
import { hex_md5 } from '@/utils/md5'
export default {
props: {
//用户ID
uid: {
type: Number,
default: () => 0
},
visible: {
type: Boolean,
default: () => false
}
},
data(){
var validateUsername = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入用户名'));
} else {
callback();
}
};
var validatePhone = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入手机号'));
} else if(!/^1[0-9]{10}$/.test(value)){
callback(new Error('请输入正确的手机号'));
} else {
callback();
}
};
var validatePass = (rule, value, callback) => {
if(this.uid == 0){
if (value === '') {
callback(new Error('请输入密码'));
} else if(value.length < 6){
callback(new Error('密码不能小于6位'));
} else {
if (this.form.checkPass !== '') {
this.$refs.ruleForm.validateField('checkPass');
}
callback();
}
}else if(this.form.password){
if (value === '') {
callback(new Error('请输入密码'));
} else if(value.length < 6){
callback(new Error('密码不能小于6位'));
} else {
if (this.form.checkPass !== '') {
this.$refs.ruleForm.validateField('checkPass');
}
callback();
}
}else{
callback();
}
};
var validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码'));
} else if (value !== this.form.password) {
callback(new Error('两次输入密码不一致!'));
} else {
callback();
}
};
var validateOldPwd = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入原密码'));
} else if (hex_md5(value) !== this.oldPassword) {
callback(new Error('密码错误!'));
} else {
callback();
}
};
return {
oldPassword: "", //编辑时,记录旧密码
form: {
name: "",
password: "",
checkPass: "",
phone: "",
opwd: ""
},
formLabelWidth: '80px',
rules: {
name: [
{ validator: validateUsername, trigger: 'blur' }
],
phone: [
{ validator: validatePhone, trigger: 'blur' }
],
password: [
{ validator: validatePass, trigger: 'blur' }
],
checkPass: [
{ validator: validatePass2, trigger: 'blur' }
],
opwd: [
{ validator: validateOldPwd, trigger: 'blur' }
]
}
}
},
methods: {
/**
* 获取提交的数据
* @date 2022/10/22
*/
getParam(){
let data = {};
if(this.form['name']){
data['name'] = this.form.name;
}
if(this.form['password']){
data['password'] = this.form.password;
}
if(this.form['phone']){
data['phone'] = this.form.phone;
}
return data;
},
/**
* 添加用户信息
* @date 2022/10/22
*/
addUserInfo(){
addUserInfo(this.getParam()).then(() => {
this.$emit('saveSuccessChange', {});
this.closeEvent();
}).catch(e => {
this.$message.error(e.msg);
});
},
/**
* 提交表单
*/
submitForm(){
this.$refs['ruleForm'].validate((valid) => {
if(valid){
this.addUserInfo();
}else{
return false;
}
});
},
/**
* 关闭事件
*/
closeEvent(){
this.$refs['ruleForm'].resetFields();
this.$emit('closeChange', {});
},
}
}
</script>
新增弹框组件创建完成后,我们在列表页(pages/mange/index.vue)中引入该组件,在打开新增用户弹框前,将selectId 置为0表示为新增。代码如下:
import UserDailog from '@/components/UserDailog'
export default {
data () {
return {
//选择ID
selectId: 0,
//查询关键字
keyword: "",
/**
* 是否显示弹框
*/
isShowDialog: false,
/**
* 列表数据
*/
tableList: [],
/**
* 选的项
*/
multipleSelection: []
}
},
components: {
UserDailog
},
//...
methods: {
/**
* 关闭弹框
*/
closeChange(){
this.isShowDialog = false;
},
/**
* 新增用户信息
*/
addUserEvent(){
this.selectId = 0;
this.isShowDialog = true;
},
//...
}
}
列表html部分引入组件,代码如下:
<UserDailog :visible="isShowDialog"
:uid="selectId"
@closeChange="closeChange"
@saveSuccessChange="updateUserList"
></UserDailog>
并在新增按钮添加打开弹框事件,代码如下:
<el-button size="small" type="primary" @click="addUserEvent">新增</el-button>
此时,我们可以看到新增弹框界面了,如下图:
现在可以添加多条数据,进行筛选操作了。如添加test1、test2、test3、tom1、tom2,创建完后列表如下图:
当我们在账号输入框中输入test,点击查询则只会显示包含test的账号,如下图:
在账号输入框中输入tom,点击查询则只会显示包含tom的账号,如下图:
这里列表查询、条件筛选和新增用户功能则完成了,接下来我们需要来完成修改数据功能。
1.3 修改数据
在“1.2 新增数据”中,我们已经完成了db/model/user.js中的编辑部分的代码功能,这里我们只需要在pages/mange/index.vue中添加打开编辑弹框,并传入选中数据ID。代码如下:
methods: {
/**
* 编辑用户信息
* @param {Object} id
*/
editUserEvent(id){
this.selectId = id;
this.isShowDialog = true;
},
}
当弹框为编辑状态时,需要获取当前用户的信息,所在在db/model/user.js中需要添加通过ID获取用户信息的功能函数,直接通过get()函数获取指定用户信息即可。代码如下:
/**
* 通过ID获取用户信息
*/
export const getUserInfoById = id => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName);
//通过ID获取数据
let data = store.get(id);
data.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
data.onsuccess = function(e){
let result = e.target.result;
if(result){
delete result['accesstoken'];
resolve(
rJson(1, result, '获取成功~')
)
}else{
reject(
rJson(0, e, '数据不存在~')
);
}
}
});
}
api/index.js中添加编辑和获取用户信息接口,代码如下:
import { toggleUser, getUserInfoById } from '@/db/model/user'
/**
* 获取用户信息
*/
export const getUserById = id => {
return getUserInfoById(id);
}
/**
* 编辑用户信息
*/
export const editUserInfo = param => {
return toggleUser(param);
}
编辑的时候,不是所有信息都是必填的,其实在“1.2 新增数据”的JS部分代码中,已经完成此部分功能。用户的密码在修改时,是非必填的,只有填入新密码时才会交验;另外修改用户信息,需要输入原密码 进行校验,校验错误进无法进行保存。
此时UserDialog/index.vue中的JS部分修改如下:
import { getUserById, addUserInfo, editUserInfo } from '@/api'
import { hex_md5 } from '@/utils/md5'
export default {
props: {
//用户ID
uid: {
type: Number,
default: () => 0
},
visible: {
type: Boolean,
default: () => false
}
},
data(){
var validateUsername = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入用户名'));
} else {
callback();
}
};
var validatePhone = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入手机号'));
} else if(!/^1[0-9]{10}$/.test(value)){
callback(new Error('请输入正确的手机号'));
} else {
callback();
}
};
var validatePass = (rule, value, callback) => {
if(this.uid == 0){
if (value === '') {
callback(new Error('请输入密码'));
} else if(value.length < 6){
callback(new Error('密码不能小于6位'));
} else {
if (this.form.checkPass !== '') {
this.$refs.ruleForm.validateField('checkPass');
}
callback();
}
}else if(this.form.password){
if (value === '') {
callback(new Error('请输入密码'));
} else if(value.length < 6){
callback(new Error('密码不能小于6位'));
} else {
if (this.form.checkPass !== '') {
this.$refs.ruleForm.validateField('checkPass');
}
callback();
}
}else{
callback();
}
};
var validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码'));
} else if (value !== this.form.password) {
callback(new Error('两次输入密码不一致!'));
} else {
callback();
}
};
var validateOldPwd = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入原密码'));
} else if (hex_md5(value) !== this.oldPassword) {
callback(new Error('密码错误!'));
} else {
callback();
}
};
return {
oldPassword: "", //编辑时,记录旧密码
form: {
name: "",
password: "",
checkPass: "",
phone: "",
opwd: ""
},
formLabelWidth: '80px',
rules: {
name: [
{ validator: validateUsername, trigger: 'blur' }
],
phone: [
{ validator: validatePhone, trigger: 'blur' }
],
password: [
{ validator: validatePass, trigger: 'blur' }
],
checkPass: [
{ validator: validatePass2, trigger: 'blur' }
],
opwd: [
{ validator: validateOldPwd, trigger: 'blur' }
]
}
}
},
watch: {
uid(){
if(this.uid!=0){
this.updateUserInfo();
}
}
},
methods: {
/**
* 获取用户信息
*/
updateUserInfo(){
getUserById(this.uid).then(res => {
if(res.code==1&&res['data']){
this.form['name'] = res.data.name;
this.form['phone'] = res.data.phone;
this.oldPassword = res.data.password;
}
}).catch(e => {
this.$message.error(e.msg);
this.closeEvent();
// console.error(e);
})
},
/**
* 获取提交的数据
*/
getParam(){
let data = {};
if(this.form['name']){
data['name'] = this.form.name;
}
if(this.form['password']){
data['password'] = this.form.password;
}
if(this.form['phone']){
data['phone'] = this.form.phone;
}
return data;
},
/**
* 添加用户信息
*/
addUserInfo(){
addUserInfo(this.getParam()).then(() => {
this.$emit('saveSuccessChange', {});
this.closeEvent();
}).catch(e => {
this.$message.error(e.msg);
});
},
/**
* 编辑用户信息
*/
editUserInfo(){
editUserInfo({
id: this.uid,
...this.getParam()
}).then(() => {
this.$emit('saveSuccessChange', {});
this.closeEvent();
}).catch(e => {
this.$message.error(e.msg);
});
},
/**
* 提交表单
*/
submitForm(){
this.$refs['ruleForm'].validate((valid) => {
if(valid){
//新增用户
if(this.uid==0){
this.addUserInfo();
}
//编辑用户
else{
this.editUserInfo();
}
}else{
return false;
}
});
},
/**
* 关闭事件
*/
closeEvent(){
this.$refs['ruleForm'].resetFields();
this.$emit('closeChange', {});
},
}
}
编辑界面如下图:
当我们需要修改用户名或手机号是,是必须输入原密码才能校验成功并进行保存。当密码框输入新密码后,则会显示再次确认密码框,不输入则非必填项。如将tom2修改为Peter,则列表则会更新为最新数据,如下图:
1.4 删除某条数据
删除单表数据,直接通过delete(’id‘)即可,在db/model/user.js中添加deleteUserById函数,代码如下:
/**
* 通过ID删除用户信息
*/
export const deleteUserById = id => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
//删除指定用户信息
let res = store.delete(id);
res.onerror = function(e){
reject(
rJson(0, e, '操作出错了~')
);
}
res.onsuccess = function(){
resolve(
rJson(1, null, '删除成功~')
)
}
});
}
api/index.js添加deleteUserInfo函数,代码如下:
import { deleteUserById } from '@/db/model/user'
/**
* 删除用户信息
*/
export const deleteUserInfo = id => {
return deleteUserById(id);
}
pages/mange/index.vue中添加删除方法,代码如下:
methods: {
/**
* 删除用户信息
* @param {Object} id
*/
deleteEvent(id){
this.$confirm('确认要删除该用户吗?', '提示', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(res => {
deleteUserInfo(id).then(() => {
this.$message.success('删除成功!');
this.updateUserList();
}).catch(e => {
this.$message.error(e.msg);
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
}
}
给表格中的删除按钮绑定删除事件,代码如下:
<el-button type="danger"
size="mini"
:disabled="userInfo.id==scope.row.id"
icon="el-icon-delete"
circle
@click="deleteEvent(scope.row.id)"
></el-button>
删除成功后,调用updateUserList()函数刷新数据列表即可。
1.5 删除选中多条数据
删除多项则需要使用到游标相关知识点了,在db/model/user.js中添加deleteUserByIds函数,用来删除多条数据记录。通过openCursor()函数,对用户表进行遍历,通过includes判断遍历数据ID是否在删除数组中,在则直接调用delete()函数(注:这里不需要指定唯一ID,当前游标指向当前遍历数据实例对象)。
/**
* 通过ID删除多条用户信息
*/
export const deleteUserByIds = ids => {
return new Promise((resolve, reject) => {
if(Array.isArray(ids)){
//打开游标
let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
//打开游标
let cursor = store.openCursor();
cursor.onerror = function(e){
reject(
rJson(0, e, '操作出错了~')
);
}
cursor.onsuccess = function(e){
let result = e.target.result;
if(result){
if(ids.includes(result.key)){
result.delete();
}
result.continue();
}else{
resolve(
rJson(1, null, '删除成功~')
)
}
}
}else{
reject(
rJson(0, e, '请传入数组形式ID数据~')
);
}
//end
});
}
api/index.js中添加删除多项数据功能函数,代码如下:
import { deleteUserByIds } from '@/db/model/user'
/**
* 删除选择中项的用户信息
*/
export const deleteUserChecked = ids => {
return deleteUserByIds(ids);
}
pages/mange/index.vue中添加删除多项数据的方法,代码如下:
methods: {
/**
* 删除选中的ID项
*/
deleteSelectedUser(){
if(this.multipleSelection.length==0){
this.$message({
type: 'info',
message: '请选择删除项'
});
return;
}
this.$confirm('确认要删除选中的用户吗?', '提示', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(res => {
deleteUserChecked(this.multipleSelection.map(item => item.id)).then(() => {
this.$message.success('删除成功!');
this.updateUserList();
}).catch(e => {
this.$message.error(e.msg);
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
}
}
再给多项删除按钮添加绑定事件,代码如下:
<el-button size="small" type="danger" @click="deleteSelectedUser">删除</el-button>
到此为止,用户管理的增删除改查功能就全部完成了;这里讲解比较碎片化,如果不清楚地方,可以留言询问;如有不足之处,欢迎指出。
二、年级管理
年级管理的增删改查就不细讲了,增删改查也不复杂,可以按照“一、管理员列表” 中的功能进行复制,修改相应参数数据即可,都是大同小异。
2.1 数据库操作文件
创建db/model/grade.js,代码如下:
import { DBIsLoadSuccess, openTransactionIndex, CONST_READ } from '@/db'
import { rJson } from '@/utils/utils'
let storeName = 'grade';
/**
* 获取年级列表
*/
export const loadGradeAllList = name => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName);
//获取所有数据
let alls = store.getAll();
alls.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
alls.onsuccess = function(e){
let result = e.target.result;
if(result){
let rData = result;
if(name){
rData = result.filter(item => item.name.includes(name));
}
resolve(
rJson(1, rData, '获取成功~')
)
}else{
reject(
rJson(0, null, '未查询到数据~')
)
}
// console.log('store', result);
}
});
}
/**
* 增加 或 编辑 年级信息
*/
export const toggleGrade = data => {
return new Promise((resolve, reject) => {
//打开游标
let {store, index} = openTransactionIndex(storeName, 'name', CONST_READ.READWRITE);
let res;
//用户ID存在,则为编辑
if(data['id']&&data.id!=0){
data['updatetime'] = new Date().getTime();
//获取原数据
res = store.get(data.id);
res.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(e){
let result = e.target.result;
if(result){
//合并数据,并保存
res = store.put(Object.assign(result, data));
res.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(){
resolve(
rJson(1, null, '保存成功~')
)
}
}else{
reject(
rJson(0, e, '年级不存在~')
);
}
}
}
//新增(需要判断用户名是否已存在)
else{
//通过索引 获取用户名,判断用户名是否已存在
res = index.getKey(data.name);
res.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(e){
let result = e.target.result;
//如果用户名已存在,返回错误信息
if(result){
reject(
rJson(0, e, '该年级已存在~')
);
}
//用户名不存在,则直接添加
else{
data['createtime'] = new Date().getTime();
data['updatetime'] = new Date().getTime();
res = store.add(data);
res.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(){
resolve(
rJson(1, null, '保存成功~')
)
}
}
}
}
});
}
/**
* 通过ID删除 年级信息
*/
export const deleteGradeById = id => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
//删除指定用户信息
let res = store.delete(id);
res.onerror = function(e){
reject(
rJson(0, e, '操作出错了~')
);
}
res.onsuccess = function(){
resolve(
rJson(1, null, '删除成功~')
)
}
});
}
/**
* 通过ID删除多条 年级信息
*/
export const deleteGradeByIds = ids => {
return new Promise((resolve, reject) => {
if(Array.isArray(ids)){
//打开游标
let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
//打开游标
let cursor = store.openCursor();
cursor.onerror = function(e){
reject(
rJson(0, e, '操作出错了~')
);
}
cursor.onsuccess = function(e){
let result = e.target.result;
if(result){
if(ids.includes(result.key)){
result.delete();
}
result.continue();
}else{
resolve(
rJson(1, null, '删除成功~')
)
}
}
}else{
reject(
rJson(0, e, '请传入数组形式ID数据~')
);
}
});
}
2.2 api接口
api/index.js中添加年级部分接口函数,代码如下:
import {
loadGradeAllList,
toggleGrade,
deleteGradeById,
deleteGradeByIds
} from '@/db/model/grade'
/**
* 获取年级列表
*/
export const gradeAllList = keyword => {
return loadGradeAllList(keyword);
}
/**
* 添加 或 修改指定年级信息
*/
export const toggleGradeInfo = name => {
return toggleGrade(name);
}
/**
* 删除指定年级
*/
export const deleteGradeInfo = id => {
return deleteGradeById(id);
}
/**
* 删除指定多项年级信息
*/
export const deleteGradeChecked = ids => {
return deleteGradeByIds(ids);
}
2.3 列表页面
打开年级列表页面pages/grade/index.vue,添加html、样式和JS部分功能。
html代码部分:
<template>
<div class="index-wrap">
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>年级列表</el-breadcrumb-item>
</el-breadcrumb>
<br /><br />
<div class="filter-wrap">
<div class="item left">
<el-form :inline="true" class="demo-form-inline">
<el-form-item label="年级名称">
<el-input size="small" v-model="keyword" placeholder="请输入年级名称"></el-input>
</el-form-item>
<el-form-item>
<el-button size="small" type="primary" @click="updateList">查询</el-button>
</el-form-item>
</el-form>
</div>
<div class="item right">
<el-form :inline="true" class="demo-form-inline">
<el-form-item>
<el-button size="small" type="primary" @click="addEvent">新增</el-button>
<el-button size="small" type="info" @click="deleteCheckedEvent">删除</el-button>
</el-form-item>
</el-form>
</div>
</div>
<div class="table-wrap">
<el-table
:data="tableList"
@selection-change="selectionChange"
style="width: 100%">
<el-table-column type="selection" label="选择" width="50"> </el-table-column>
<el-table-column prop="name" label="年级名称"></el-table-column>
<el-table-column prop="createtime" label="创建日期"></el-table-column>
<el-table-column prop="updatetime" label="更新日期"></el-table-column>
<el-table-column label="操作" width="150">
<template slot-scope="scope">
<el-button type="primary" size="mini" icon="el-icon-edit" circle @click="editEvent(scope.row.id, scope.row.name)"></el-button>
<el-button type="danger" size="mini" icon="el-icon-delete" circle @click="deleteEvent(scope.row.id)"></el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
样式部分:
.index-wrap{
padding: 20px;
}
.filter-wrap{
display: table;
width: 100%;
.item{
display: table-cell;
vertical-align: middle;
&.left{
text-align: left;
}
&.right{
text-align: right;
}
}
}
JS部分:
import { gradeAllList, toggleGradeInfo, deleteGradeInfo, deleteGradeChecked } from '@/api'
import { formatDate } from '@/utils/utils'
export default {
data () {
return {
/**
* 搜索关键词
*/
keyword: "",
/**
* 列表数据
*/
tableList: [],
/**
* 选中项
*/
multipleSelection: []
}
},
created() {
this.updateList();
},
methods: {
/**
* 获取列表数据
*/
updateList(){
gradeAllList(this.keyword).then(res => {
if(res.code==1&&Array.isArray(res.data)){
this.tableList = res.data.map(item => {
item['createtime'] = formatDate(item.createtime);
item['updatetime'] = formatDate(item.updatetime);
return item;
});
}
}).catch(msg => {
console.log('msg', msg);
});
//end
},
/**
* 添加事件
*/
addEvent(){
this.$prompt('请输入年级名称', '提示', {
confirmButtonText: '保存',
cancelButtonText: '取消',
inputValidator: function(value){
if(value&&value.toString().length>0){
return true;
}else{
return "请输入年级名称";
}
},
inputErrorMessage: "请输入年级名称"
}).then(({ value }) => {
toggleGradeInfo({
name: value
}).then(res => {
this.$message.success('添加成功');
this.updateList();
}).catch(e => {
this.$message({
type: 'info',
message: e.msg
});
});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消'
});
});
},
/**
* 编辑事件
*/
editEvent(id, name){
this.$prompt('请输入年级名称', '提示', {
confirmButtonText: '保存',
cancelButtonText: '取消',
inputValidator: function(value){
if(value&&value.toString().length>0){
return true;
}else{
return "请输入年级名称";
}
},
inputValue: name,
inputErrorMessage: "请输入年级名称"
}).then(({ value }) => {
toggleGradeInfo({
id: id,
name: value
}).then(res => {
this.$message.success('保存成功');
this.updateList();
}).catch(e => {
this.$message({
type: 'info',
message: e.msg
});
});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消'
});
});
},
/**
* 删除事件
* @param {Object} id
*/
deleteEvent(id){
this.$confirm('确认要删除该年级吗?', '提示', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(res => {
deleteGradeInfo(id).then(() => {
this.$message.success('删除成功!');
this.updateList();
}).catch(e => {
this.$message.error(e.msg);
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
/**
* check 选中项项值
* @param {Object} val
*/
selectionChange(val){
this.multipleSelection = val;
},
/**
* 删除多项指定年级信息
*/
deleteCheckedEvent(){
if(this.multipleSelection.length==0){
this.$message({
type: 'info',
message: '请选择删除项'
});
return;
}
this.$confirm('确认要删除选中的年级吗?', '提示', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(res => {
deleteGradeChecked(this.multipleSelection.map(item => item.id)).then(() => {
this.$message.success('删除成功!');
this.updateList();
}).catch(e => {
this.$message.error(e.msg);
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
}
//end
}
}
到此为止,年级部分功能就完成了;由于这里添加信息只有年级名称,所以使用了Element的this.$prompt弹框进行添加和编辑。界面效果如下:
列表页面:
新增页面:
三、教师列表
这里先讲教师列表的功能实现,因为班级管理中需要关联对应班主任,这项为必填项;而教师对应的班级是非必填项。
这部分和前面并无太大差异,还是常规的新删改查部分功能,所以也不作功能分解,直接按代码操作即可。
3.1 数据库操作文件
db/model/teacher.js代码如下:
import { DBIsLoadSuccess, openTransactionIndex, CONST_READ } from '@/db'
import { rJson } from '@/utils/utils'
let storeName = 'teacher';
/**
* 获取 教师列表
*/
export const loadTeacherAllList = name => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName);
//获取所有数据
let alls = store.getAll();
alls.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
alls.onsuccess = function(e){
let result = e.target.result;
if(result){
let rData = result;
if(name){
rData = result.filter(item => item.name.includes(name));
}
resolve(
rJson(1, rData, '获取成功~')
)
}else{
reject(
rJson(0, null, '未查询到数据~')
)
}
// console.log('store', result);
}
});
}
/**
* 获取教师信息
*/
export const getTecharInfoById = id => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName);
//通过ID获取数据
let data = store.get(id);
data.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
data.onsuccess = function(e){
let result = e.target.result;
if(result){
resolve(
rJson(1, result, '获取成功~')
)
}else{
reject(
rJson(0, e, '数据不存在~')
);
}
}
});
}
/**
* 增加 或 编辑 教师信息
*/
export const toggleTeacher = data => {
return new Promise((resolve, reject) => {
//打开游标
let {store, index} = openTransactionIndex(storeName, 'name', CONST_READ.READWRITE);
let res;
//ID存在,则为编辑
if(data['id']&&data.id!=0){
data['updatetime'] = new Date().getTime();
//获取原数据
res = store.get(data.id);
res.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(e){
let result = e.target.result;
if(result){
//合并数据,并保存
res = store.put(Object.assign(result, data));
res.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(){
resolve(
rJson(1, null, '保存成功~')
)
}
}else{
reject(
rJson(0, e, '年级不存在~')
);
}
}
}
//新增(需要判断是否已存在)
else{
//通过索引获取,判断是否已存在
res = index.getKey(data.name);
res.onerror = function(){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(e){
let result = e.target.result;
//如果已存在,返回错误信息
if(result){
reject(
rJson(0, e, '该教师已存在~')
);
}
//不存在,则直接添加
else{
data['createtime'] = new Date().getTime();
data['updatetime'] = new Date().getTime();
res = store.add(data);
res.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(){
resolve(
rJson(1, null, '保存成功~')
)
}
}
//if 2 end
}
//索引 End
}
//if end
});
}
/**
* 通过ID删除教师信息
*/
export const deleteTeacherById = id => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
//删除指定信息
let res = store.delete(id);
res.onerror = function(e){
reject(
rJson(0, e, '操作出错了~')
);
}
res.onsuccess = function(){
resolve(
rJson(1, null, '删除成功~')
)
}
});
}
/**
* 通过ID删除多条教师信息
*/
export const deleteTeacherByIds = ids => {
return new Promise((resolve, reject) => {
if(Array.isArray(ids)){
//打开游标
let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
//打开游标
let cursor = store.openCursor();
cursor.onerror = function(e){
reject(
rJson(0, e, '操作出错了~')
);
}
cursor.onsuccess = function(e){
let result = e.target.result;
if(result){
if(ids.includes(result.key)){
result.delete();
}
result.continue();
}else{
resolve(
rJson(1, null, '删除成功~')
)
}
}
}else{
reject(
rJson(0, e, '请传入数组形式ID数据~')
);
}
});
}
3.2 api接口
api/index.js文件添加以下代码:
import {
loadTeacherAllList,
toggleTeacher,
deleteTeacherById,
deleteTeacherByIds,
getTecharInfoById
} from '@/db/model/teacher'
/**
* 获取教师列表
*/
export const getTeachersList = name => {
return loadTeacherAllList(name);
}
/**
* 新增或修改教师信息
*/
export const toggerTeacherInfo = params => {
return toggleTeacher(params);
}
/**
* 通过ID获取教师信息
*/
export const loadTeacherById = id => {
return getTecharInfoById(id);
}
/**
* 单个教师信息删除
*/
export const deleteTeacherInfo = id => {
return deleteTeacherById(id);
}
/**
* 删除指定多个教师信息
*/
export const deleteSelectedTeacherInfo = ids => {
return deleteTeacherByIds(ids);
}
3.3 新增页面
在components中添加TeacherDialog/index.vue新增页面组件,html部分代码:
<template>
<el-dialog :title="uid!=0?'编辑':'新增'" :visible="visible" @close="closeEvent" width="420px" class="dialog-wrap">
<el-form :model="form" :rules="rules" status-icon ref="ruleForm">
<el-form-item label="教师姓名" :label-width="formLabelWidth" required prop="name">
<el-input v-model="form.name" autocomplete="off" size="small"></el-input>
</el-form-item>
<el-form-item label="户籍" :label-width="formLabelWidth" required prop="registration">
<el-input v-model="form.registration" autocomplete="off" size="small"></el-input>
</el-form-item>
<el-form-item label="手机号" :label-width="formLabelWidth" required prop="phone">
<el-input v-model="form.phone" autocomplete="off" size="small"></el-input>
</el-form-item>
<el-form-item label="居住地址" :label-width="formLabelWidth" required prop="address">
<el-input v-model="form.address" autocomplete="off" size="small"></el-input>
</el-form-item>
<el-form-item label="出生日期" :label-width="formLabelWidth" required prop="birthday">
<el-date-picker v-model="form.birthday" value-format="yyyy-MM-dd" type="date" placeholder="选择日期"></el-date-picker>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button size="small" @click="closeEvent">取 消</el-button>
<el-button size="small" type="primary" @click="submitForm">保 存</el-button>
</div>
</el-dialog>
</template>
js部分代码:
<script>
import { toggerTeacherInfo, loadTeacherById } from '@/api'
import { formatDate } from '@/utils/utils'
export default {
props: {
//用户ID
uid: {
type: Number,
default: () => 0
},
visible: {
type: Boolean,
default: () => false
}
},
data(){
return {
formLabelWidth: '80px',
gradeOptions: [],
classOptions: [],
dateValue: "",
form: {
name: "",
registration: "",
phone: "",
address: "",
birthday: ""
},
rules: {
name: [
{ required: true, message: '请输入教师姓名', trigger: 'blur' },
{ required: true, message: '请输入教师姓名', trigger: 'change' },
],
registration: [
{ required: true, message: '请输入户籍', trigger: 'blur' },
{ required: true, message: '请输入户籍', trigger: 'change' },
],
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{ required: true, message: '请输入手机号', trigger: 'change' },
{ tel: true, message: '请输入手机号', trigger: 'blur' },
{ tel: true, message: '请输入手机号', trigger: 'change' },
],
address: [
{ required: true, message: '请输入现居住地址', trigger: 'blur' },
{ required: true, message: '请输入现居住地址', trigger: 'change' },
],
birthday: [
{ required: true, message: '请选择出生日期', trigger: 'blur' },
{ required: true, message: '请选择出生日期', trigger: 'change' },
{ date: true, message: '请选择出生日期', trigger: 'blur' },
{ date: true, message: '请选择出生日期', trigger: 'change' },
]
}
}
},
watch: {
uid(){
if(this.uid!=0){
this.updateClassInfo();
}
}
},
methods: {
/**
* 获取都老师信息
*/
updateClassInfo(){
loadTeacherById(this.uid).then(res => {
if(res.code==1){
this.form = {
name: res.data['name'],
registration: res.data['registration'],
phone: res.data['phone'],
address: res.data['address'],
birthday: res.data['birthday']
}
}
}).catch(e => {
console.error(e);
})
},
/**
* 获取保存数据
*/
getParams(){
let { name, registration, phone, address, birthday } = this.form;
return {
name, registration, phone, address, birthday
}
},
/**
* 添加教师信息
*/
addUserInfo(){
let param = this.getParams();
toggerTeacherInfo(param).then(res => {
if(res.code==1){
this.$message.success('保存成功');
this.$emit('saveChange', {});
}
}).catch(e => {
this.$message.success(e.msg);
});
},
/**
* 编辑教师信息
*/
editUserInfo(){
let param = this.getParams();
param['id'] = this.uid;
toggerTeacherInfo(param).then(res => {
if(res.code==1){
this.$message.success('保存成功');
this.$emit('saveChange', {});
}
}).catch(e => {
this.$message.success(e.msg);
});
},
/**
* 提交表单
*/
submitForm(){
// console.log(this.form)
this.$refs['ruleForm'].validate((valid) => {
if(valid){
//新增
if(this.uid==0){
this.addUserInfo();
}
//编辑
else{
this.editUserInfo();
}
}else{
return false;
}
});
},
/**
* 关闭事件
*/
closeEvent(){
this.$refs['ruleForm'].resetFields();
this.$emit('closeChange', {});
},
}
}
</script>
添加界面如下:
3.4 列表页面
在pages目录中teacher/index.vue添加列表页面,html部分代码如下:
<template>
<div class="index-wrap">
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>教师列表</el-breadcrumb-item>
</el-breadcrumb>
<br /><br />
<div class="filter-wrap">
<div class="item left">
<el-form :inline="true" class="demo-form-inline">
<el-form-item label="教师姓名">
<el-input size="small" placeholder="请输入教师姓名" v-model="keyword"></el-input>
</el-form-item>
<el-form-item>
<el-button size="small" type="primary" @click="updateList">查询</el-button>
</el-form-item>
</el-form>
</div>
<div class="item right">
<el-form :inline="true" class="form-inline">
<el-form-item>
<el-button size="small" type="primary" @click="showAddDialog">新增</el-button>
<el-button size="small" type="info" @click="deleteSelectedTeacher">删除</el-button>
</el-form-item>
</el-form>
</div>
</div>
<div class="table-wrap">
<el-table
@selection-change="selectionChange"
:data="tableList"
style="width: 100%">
<el-table-column type="selection" label="选择" width="50"> </el-table-column>
<el-table-column prop="name" label="教师姓名"></el-table-column>
<el-table-column prop="registration" label="户籍"></el-table-column>
<el-table-column prop="address" label="居住地址"></el-table-column>
<el-table-column prop="age" label="年龄" width="80">
<template slot-scope="scope">
<span>{{scope.row.birthday | filterAge}}</span>
</template>
</el-table-column>
<el-table-column prop="createtime" label="创建日期" width="180"></el-table-column>
<el-table-column prop="updatetime" label="更新日期" width="180"></el-table-column>
<el-table-column label="操作" width="150">
<template slot-scope="scope">
<el-button type="primary" size="mini" icon="el-icon-edit" circle @click="editDialog(scope.row.id)"></el-button>
<el-button type="danger" size="mini" icon="el-icon-delete" circle @click="deleteTeacherEvent(scope.row.id)"></el-button>
</template>
</el-table-column>
</el-table>
</div>
<TeacherDialog :uid="selectId" :visible="isShowDialog" @closeChange="closeChange" @saveChange="saveChange"></TeacherDialog>
</div>
</template>
js部分代码:
<script>
import TeacherDialog from '@/components/TeacherDialog'
import { getTeachersList, toggerTeacherInfo, deleteTeacherInfo, deleteSelectedTeacherInfo } from '@/api'
import { formatDate } from '@/utils/utils'
export default {
data () {
return {
//编辑选择用户ID
selectId: 0,
//搜索关键词
keyword: "",
/**
* 是否显示弹框
*/
isShowDialog: false,
/**
* 列表数据
*/
tableList: [],
/**
* 选择项
*/
multipleSelection: []
}
},
components: {
TeacherDialog
},
created() {
this.updateList();
},
filters: {
filterAge(val){
let current = new Date(),
bDate = new Date(val);
return current.getFullYear() - bDate.getFullYear();
}
},
methods: {
/**
* 获取教师列表数据
*/
updateList(){
getTeachersList(this.keyword).then(res => {
if(res.code==1){
this.tableList = res.data.map(item => {
item['createtime'] = formatDate(item.createtime);
item['updatetime'] = formatDate(item.updatetime);
return item;
});
}
//if end
}).catch(msg => {
console.error(msg);
});
//ajax end
},
/**
* 编辑教师信息
*/
editDialog(id){
this.selectId = id;
this.isShowDialog = true;
},
/**
* 显示弹框事件
*/
showAddDialog(){
this.isShowDialog = true;
},
/**
* 新增教师保存事件
*/
saveChange(){
this.updateList();
this.isShowDialog = false;
},
/**
* 关闭弹框事件
*/
closeChange(){
this.selectId = 0;
this.isShowDialog = false;
},
/**
* 删除指定教师信息
* @param {Object} id
*/
deleteTeacherEvent(id){
this.$confirm('确认要删除该教师信息吗?', '提示', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(res => {
deleteTeacherInfo(id).then(() => {
this.$message.success('删除成功!');
this.updateList();
}).catch(e => {
this.$message.error(e.msg);
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
/**
* check 选中项项值
* @param {Object} val
*/
selectionChange(val){
this.multipleSelection = val;
},
/**
* 删除指定多个教师信息
*/
deleteSelectedTeacher(){
if(this.multipleSelection.length==0){
this.$message({
type: 'info',
message: '请选择删除项'
});
return;
}
this.$confirm('确认要删除选中的教师信息吗?', '提示', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(res => {
deleteSelectedTeacherInfo(this.multipleSelection.map(item => item.id)).then(() => {
this.$message.success('删除成功!');
this.updateList();
}).catch(e => {
this.$message.error(e.msg);
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
}
//
}
}
</script>
列表界面如下:
四、班级管理
班级这部分由于关联了教师ID和年级ID,所以在做查询时,会稍微复杂点,同时需要之前的grade.js和teacher.js中增加单独查询功能,下面会一一阐述。
4.1 数据库操作文件
db/model/classify.js代码:
import { DBIsLoadSuccess, openTransactionIndex, CONST_READ } from '@/db'
import { rJson } from '@/utils/utils'
import { getTeacherByIdsCursor } from './teacher.js'
import { getGradeByIdsCursor } from './grade.js'
let storeName = 'classify';
/**
* 获取 班级信息
*/
export const loadClassAllList = async (name) => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName);
//获取所有数据
let alls = store.getAll();
alls.onerror = function(e){
console.log('error', e)
reject(
rJson(0, e, '查询出错了~')
);
}
alls.onsuccess = function(e){
let result = e.target.result;
if(result){
let rData = result;
if(name){
rData = result.filter(item => item.name.includes(name));
}
resolve(
rJson(1, rData, '获取成功~')
)
}else{
reject(
rJson(0, null, '未查询到数据~')
)
}
// console.log('store', result);
}
});
}
/**
* 通过ID获取 班级信息
*/
export const getClassInfoById = id => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName);
//通过ID获取数据
let data = store.get(id);
data.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
data.onsuccess = function(e){
let result = e.target.result;
if(result){
resolve(
rJson(1, result, '获取成功~')
)
}else{
reject(
rJson(0, e, '数据不存在~')
);
}
}
});
}
/**
* 通过年级ID获取对应班级信息
*/
export const getClassInfoByKey = key => {
return new Promise((resolve, reject) => {
//打开游标
let {store, cursor} = openTransactionIndex(storeName, 'gid'),
reData = [];
cursor.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
cursor.onsuccess = function(e){
let result = e.target.result;
if(result){
if(result.key==key){
reData.push({
id: result.value.id,
name: result.value.name
});
}
result.continue();
}else{
resolve(
rJson(1, reData, '获取成功~')
)
// console.log('end')
}
}
});
}
/**
* 增加 或 编辑 班级信息
*/
export const toggleClass = data => {
return new Promise((resolve, reject) => {
//打开游标
let {store, index} = openTransactionIndex(storeName, 'name', CONST_READ.READWRITE);
let res;
//ID存在,则为编辑
if(data['id']&&data.id!=0){
data['updatetime'] = new Date().getTime();
//获取原数据
res = store.get(data.id);
res.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(e){
let result = e.target.result;
if(result){
//合并数据,并保存
res = store.put(Object.assign(result, data));
res.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(){
resolve(
rJson(1, null, '保存成功~')
)
}
}else{
reject(
rJson(0, e, '年级不存在~')
);
}
}
}
//新增(需要判断是否已存在)
else{
//通过索引获取,判断是否已存在
res = index.getKey(data.name);
res.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(e){
let result = e.target.result;
//如果已存在,返回错误信息
if(result){
reject(
rJson(0, e, '该年级已存在~')
);
}
//不存在,则直接添加
else{
data['createtime'] = new Date().getTime();
data['updatetime'] = new Date().getTime();
res = store.add(data);
res.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(){
resolve(
rJson(1, null, '保存成功~')
)
}
}
//if 2 end
}
//索引 End
}
//if end
});
}
/**
* 通过ID删除班级
*/
export const deleteClassById = id => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
//删除指定信息
let res = store.delete(id);
res.onerror = function(e){
reject(
rJson(0, e, '操作出错了~')
);
}
res.onsuccess = function(){
resolve(
rJson(1, null, '删除成功~')
)
}
});
}
/**
* 通过ID删除多条班级
*/
export const deleteClassByIds = ids => {
return new Promise((resolve, reject) => {
if(Array.isArray(ids)){
//打开游标
let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
//打开游标
let cursor = store.openCursor();
cursor.onerror = function(e){
reject(
rJson(0, e, '操作出错了~')
);
}
cursor.onsuccess = function(e){
let result = e.target.result;
if(result){
if(ids.includes(result.key)){
result.delete();
}
result.continue();
}else{
resolve(
rJson(1, null, '删除成功~')
)
}
}
}else{
reject(
rJson(0, e, '请传入数组形式ID数据~')
);
}
//end
});
}
4.2 api接口
api/index.js中添加班级接口,代码如下:
import {
loadClassAllList,
toggleClass,
getClassInfoById,
deleteClassById,
deleteClassByIds,
getClassInfoByKey
} from '@/db/model/classify'
/**
* 获取班级列表
*/
export const getClassList = name => {
return loadClassAllList(name);
}
/**
* 新增或保存 班级信息
*/
export const toggleClassInfo = param => {
return toggleClass(param);
}
/**
* 通过索引获取对应班级信息
*/
export const getClassByKey = key => {
return getClassInfoByKey(key);
}
/**
* 获取班级信息 通过ID
*/
export const getClassifyById = id => {
return getClassInfoById(id);
}
/**
* 通过ID删除指定班级信息
*/
export const deleteClassInfoById = id => {
return deleteClassById(id);
}
/**
* 通过选择中的ID删除 班级信息
*/
export const deleteClassSelectedInfoByIds = ids => {
return deleteClassByIds(ids);
}
4.3 新增班级页面
在components目录中添加ClassDialog/index.vue新增页面组件,html部分代码:
<template>
<el-dialog :title="uid!=0?'编辑':'新增'" :visible="visible" @close="closeEvent" width="420px" class="dialog-wrap">
<el-form :model="form" :rules="rules" status-icon ref="ruleForm">
<el-form-item label="班级名称" :label-width="formLabelWidth" prop="name" required>
<el-input v-model="form.name" autocomplete="off" size="small"></el-input>
</el-form-item>
<el-form-item label="选择年级" :label-width="formLabelWidth" prop="grade" required>
<el-select size="small" v-model="form.grade" placeholder="请选择">
<el-option
v-for="item in gradeOptions"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="班主任" :label-width="formLabelWidth" prop="master" required>
<el-select size="small" v-model="form.master" placeholder="请选择">
<el-option
v-for="item in masterOptions"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="授课老师">
<el-table
:data="courseList"
size="mini"
border
style="width: 100%">
<el-table-column prop="name" label="名称">
</el-table-column>
<el-table-column label="教师名称" width="180">
<template slot-scope="scope">
<el-select size="small" v-model="scope.row.tid" placeholder="请选择">
<el-option
v-for="item in masterOptions"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button size="small" @click="closeEvent">取 消</el-button>
<el-button size="small" type="primary" @click="submitForm">保 存</el-button>
</div>
</el-dialog>
</template>
这里与其他新增页面不同之处在于加载时,同时需要获取年级和教师数据列表,用于下拉选项,这两个接口已在api/index.js定义过,直接调用即可。
这里也作了些偷懒操作,每个班级所对应课程并未作动态添加功能,而是写死在新增页面。保存的时候是以数组形式存库的,所以在编辑的时候,通过班级ID获取到班级信息,需将拿到ts字段对应信息,重新赋值给courseList。
js代码部分:
<script>
import { gradeAllList, getTeachersList, toggleClassInfo, getClassifyById } from '@/api'
export default {
props: {
//用户ID
uid: {
type: Number,
default: () => 0
},
visible: {
type: Boolean,
default: () => false
}
},
data(){
return {
formLabelWidth: '80px',
gradeOptions: [], //年级
masterOptions: [], //教师
courseList: [
{"name": "语文", "tid": ""},
{"name": "数据", "tid": ""},
{"name": "英文", "tid": ""},
],
form: {
name: "",
master: "",
grade: ""
},
rules: {
name: [
{ required: true, message: '请输入班级名称', trigger: 'blur' },
{ required: true, message: '请输入班级名称', trigger: 'change' },
],
grade: [
{ required: true, message: '请选择年级', trigger: 'blur' },
{ required: true, message: '请选择年级', trigger: 'change' },
],
master: [
{ required: true, message: '请选择班主任', trigger: 'blur' },
{ required: true, message: '请选择班主任', trigger: 'change' },
],
}
}
},
watch: {
uid(){
if(this.uid!=0){
this.updateClassInfo();
}
}
},
created() {
this.updatePropsInfo();
},
methods: {
/**
* 获取班级信息
*/
updateClassInfo(){
getClassifyById(this.uid).then(res => {
if(res.code==1){
this.form = {
name: res.data.name,
master: res.data.mid,
grade: res.data.gid
}
if(Array.isArray(res.data['ts'])&&res.data.ts.length>0){
this.courseList = res.data.ts;
}
}
// console.log(res);
}).catch(e => {
console.error(e);
})
},
/**
* 获取属性信息
*/
updatePropsInfo(){
Promise.all([gradeAllList(), getTeachersList()]).then(res => {
let gradeList = res[0]['data'],
teacherList = res[1]['data'];
if(Array.isArray(gradeList)){
this.gradeOptions = gradeList.map(item => item);
}
if(Array.isArray(teacherList)){
this.masterOptions = teacherList;
}
}).catch(e => {
console.error(e);
})
},
/**
* 添加班级信息
*/
addUserInfo(){
let params = this.getParams();
toggleClassInfo(params).then(res => {
if(res.code==1){
this.$message.success('保存成功');
this.$emit('saveSuccessChange', {});
}
}).catch(e => {
this.$message.success(e.msg);
console.error(e);
});
},
/**
* 编辑班级信息
*/
editUserInfo(){
let params = this.getParams();
params['id'] = this.uid;
toggleClassInfo(params).then(res => {
if(res.code==1){
this.$message.success('保存成功');
this.$emit('saveSuccessChange', {});
}
}).catch(e => {
this.$message.success(e.msg);
console.error(e);
});
},
/**
* 获取保存参数
*/
getParams(){
let { name, grade, master } = this.form;
return {
name,
gid: grade,
mid: master,
ts: this.courseList
}
},
/**
* 提交表单
*/
submitForm(){
this.$refs['ruleForm'].validate((valid) => {
if(valid){
//新增班级
if(this.uid==0){
this.addUserInfo();
}
//编辑班级
else{
this.editUserInfo();
}
}else{
return false;
}
});
},
/**
* 关闭事件
*/
closeEvent(){
this.$refs['ruleForm'].resetFields();
this.courseList = this.courseList.map(item => {
item['tid'] = "";
return item;
})
this.$emit('closeChange', {});
},
}
}
</script>
新增界面如下:
4.4 班级列表页
在pages/classify/index.vue中添加列表页面,html代码如下:
<template>
<div class="index-wrap">
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>班级列表</el-breadcrumb-item>
</el-breadcrumb>
<br /><br />
<div class="filter-wrap">
<div class="item left">
<el-form :inline="true" class="demo-form-inline">
<el-form-item label="班级名称">
<el-input size="small" placeholder="请输入班级名称" v-model="keyword"></el-input>
</el-form-item>
<el-form-item>
<el-button size="small" type="primary" @click="updateList">查询</el-button>
</el-form-item>
</el-form>
</div>
<div class="item right">
<el-form :inline="true" class="demo-form-inline">
<el-form-item>
<el-button size="small" type="primary" @click="showAddDialog">新增</el-button>
<el-button size="small" type="info" @click="deleteSelectedClass">删除</el-button>
</el-form-item>
</el-form>
</div>
</div>
<div class="table-wrap">
<el-table
@selection-change="selectionChange"
:data="tableList"
style="width: 100%">
<el-table-column type="selection" label="选择" width="50"> </el-table-column>
<el-table-column prop="name" label="班级名称"></el-table-column>
<el-table-column prop="master" label="班主任"></el-table-column>
<el-table-column prop="grade" label="年级"></el-table-column>
<el-table-column prop="createtime" label="创建日期"></el-table-column>
<el-table-column prop="updatetime" label="更新日期"></el-table-column>
<el-table-column prop="trs" label="授课教师" type="expand" width="100px">
<template slot-scope="scope">
<el-table
size="small"
:show-header="false"
:data="scope.row.ts"
style="width: 100%">
<el-table-column prop="name" width="100px"></el-table-column>
<el-table-column prop="teacher"></el-table-column>
</el-table>
</template>
</el-table-column>
<el-table-column label="操作" width="150">
<template slot-scope="scope">
<el-button type="primary" size="mini" icon="el-icon-edit" circle @click="editClassEvent(scope.row.id)"></el-button>
<el-button type="danger" size="mini" icon="el-icon-delete" circle @click="deleteEvent(scope.row.id)"></el-button>
</template>
</el-table-column>
</el-table>
</div>
<ClassDialog :visible="isShowDialog" :uid="selectedId" @closeChange="closeChange" @saveSuccessChange="saveSuccessChange"></ClassDialog>
</div>
</template>
js部分代码:
<script>
import ClassDialog from '@/components/ClassDialog'
import { formatDate } from '@/utils/utils'
import { getClassList, deleteClassInfoById, deleteClassSelectedInfoByIds } from '@/api'
export default {
data () {
return {
//选中的ID
selectedId: 0,
//搜索关键事件
keyword: "",
/**
* 是否显示弹框
*/
isShowDialog: false,
/**
* 列表数据
*/
tableList: [],
/**
* 选择项
*/
multipleSelection: []
}
},
components: {
ClassDialog
},
created() {
this.updateList();
},
methods: {
/**
* 更新地址
*/
updateList(){
getClassList(this.keyword).then(res => {
if(res.code==1){
this.tableList = res.data.map(item => {
item['createtime'] = formatDate(item.createtime);
item['updatetime'] = formatDate(item.updatetime);
return item;
});
// console.log(this.tableList)
}
}).catch(e => {
console.error(e);
})
},
/**
* 保存成功
*/
saveSuccessChange(){
this.updateList();
this.isShowDialog = false;
},
/**
* 显示弹框
*/
showAddDialog(){
this.isShowDialog = true;
},
/**
* 关闭弹框
*/
closeChange(){
this.selectedId = 0;
this.isShowDialog = false;
},
/**
* 编辑班级信息
*/
editClassEvent(id){
this.selectedId = id;
this.isShowDialog = true;
},
/**
* 删除指定班级信息
* @param {Object} id
*/
deleteEvent(id){
this.$confirm('确认要删除该班级信息吗?', '提示', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(res => {
deleteClassInfoById(id).then(() => {
this.$message.success('删除成功!');
this.updateList();
}).catch(e => {
this.$message.error(e.msg);
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
/**
* check 选中项项值
* @param {Object} val
*/
selectionChange(val){
this.multipleSelection = val;
},
/**
* 删除选中的班级信息
*/
deleteSelectedClass(){
if(this.multipleSelection.length==0){
this.$message({
type: 'info',
message: '请选择删除项'
});
return;
}
this.$confirm('确认要删除选中的班级信息吗?', '提示', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(res => {
deleteClassSelectedInfoByIds(this.multipleSelection.map(item => item.id)).then(() => {
this.$message.success('删除成功!');
this.updateList();
}).catch(e => {
this.$message.error(e.msg);
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
}
}
</script>
列表界面如下:
4.5 查询关联数据
如上图所示,现在班主任和年级信息无法显示,因为这里我们保存的是教师ID和年级ID,所以现在需要在列表查询功能中,增加master和grade两个字段,将查询到对应的数据赋值即可。
并且想要拿到对应id的name值,则需要去对应teacher表和grade表中进行查询,所以还要在对应表的操作文件中添加相应查询功能函数。通过传入的ID集进行匹配相应数据,并以ID为键名保存到新的变量值中,以便与教师列表中的ID相关联。
第一步:打开db/model/teacher.js,添加getTeacherByIdsCursor()函数,代码如下:
/**
* 通过游标获取对应数据集
*/
export const getTeacherByIdsCursor = ids => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName);
//通过ID获取数据
let cursor = store.openCursor(),
reData = {};
cursor.onerror = function(e){
reject();
}
cursor.onsuccess = function(e){
let result = e.target.result;
if(result){
if(ids.includes(result.value.id)){
reData[result.value.id] = result.value;
}
result.continue();
}else{
resolve(reData);
}
}
//end
});
}
第二步:打开db/model/grade.js,添加getGradeByIdsCursor()函数,代码如下:
/**
* 通过游标获取对应数据集
*/
export const getGradeByIdsCursor = ids => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName);
//通过ID获取数据
let cursor = store.openCursor(),
reData = {};
cursor.onerror = function(e){
reject();
}
cursor.onsuccess = function(e){
let result = e.target.result;
if(result){
if(ids.includes(result.value.id)){
reData[result.value.id] = result.value;
}
result.continue();
}else{
resolve(reData);
}
}
//end
});
}
第三步:打开db/model/classify.js文件,修改loadClassAllList()函数,代码如下:
/**
* 获取 班级信息
*/
export const loadClassAllList = async (name) => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName);
//获取所有数据
let alls = store.getAll();
alls.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
alls.onsuccess = function(e){
let result = e.target.result;
if(result){
let rData = result;
if(name){
rData = result.filter(item => item.name.includes(name));
}
let teacherIds = [];
//拿到不重复的教师ID
rData.forEach(item => {
if(!teacherIds.includes(item.mid)){
teacherIds.push(item.mid);
}
if(Array.isArray(item['ts'])&&item.ts.length>0){
item.ts.forEach(sub => {
if(!teacherIds.includes(sub.tid)){
teacherIds.push(sub.tid);
}
});
}
})
//查询关联数据
Promise.all([
getTeacherByIdsCursor(teacherIds),
getGradeByIdsCursor(rData.map(item => item.gid))
]).then(res => {
let teacher = res[0],
grade = res[1];
//重组数据
rData = rData.map(item => {
if('undefined'!==typeof teacher[item.mid]){
item['master'] = teacher[item.mid]['name'];
}
if('undefined'!==typeof grade[item.gid]){
item['grade'] = grade[item.gid]['name'];
}
//查询到授课教师信息
if(Array.isArray(item['ts'])&&item.ts.length>0){
item.ts = item.ts.map(sub => {
if('undefined'!==typeof teacher[sub.tid]){
sub['teacher'] = teacher[sub.tid]['name'];
}
return sub;
})
}
return item;
});
resolve(
rJson(1, rData, '获取成功~')
)
}).catch(e => {
reject(
rJson(0, null, '关联数据查询错误~')
)
});
}else{
reject(
rJson(0, null, '未查询到数据~')
)
}
}
});
}
此时再查看列表页,班主任和年级信息则显示出来了,如下图:
五、学员列表
5.1 数据库操作文件
db/model/student.js代码如下:
import { DBIsLoadSuccess, openTransactionIndex, CONST_READ } from '@/db'
import { rJson } from '@/utils/utils'
import { getClassByIdsCursor } from './classify.js'
let storeName = 'student';
/**
* 获取 学员列表
*/
export const loadStudentAllList = name => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName);
//获取所有数据
let alls = store.getAll();
alls.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
alls.onsuccess = function(e){
let result = e.target.result;
if(result){
let rData = result;
if(name){
rData = result.filter(item => item.name.includes(name));
}
resolve(
rJson(1, rData, '获取成功~')
)
}else{
reject(
rJson(0, null, '未查询到数据~')
)
}
// console.log('store', result);
}
});
}
/**
* 获取学员信息
*/
export const getStudentInfoById = id => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName);
//通过ID获取数据
let data = store.get(id);
data.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
data.onsuccess = function(e){
let result = e.target.result;
if(result){
resolve(
rJson(1, result, '获取成功~')
)
}else{
reject(
rJson(0, e, '数据不存在~')
);
}
}
});
}
/**
* 增加 或 编辑 员学信息
*/
export const toggleStudent = data => {
return new Promise((resolve, reject) => {
//打开游标
let {store, index} = openTransactionIndex(storeName, 'name', CONST_READ.READWRITE);
let res;
//ID存在,则为编辑
if(data['id']&&data.id!=0){
data['updatetime'] = new Date().getTime();
//获取原数据
res = store.get(data.id);
res.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(e){
let result = e.target.result;
if(result){
//合并数据,并保存
res = store.put(Object.assign(result, data));
res.onerror = function(){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(){
resolve(
rJson(1, null, '保存成功~')
)
}
}else{
reject(
rJson(0, e, '年级不存在~')
);
}
}
}
//新增(需要判断是否已存在)
else{
//通过索引获取,判断是否已存在
res = index.getKey(data.name);
res.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(e){
let result = e.target.result;
//如果用已存在,返回错误信息
if(result){
reject(
rJson(0, e, '该学员已存在~')
);
}
//不存在,则直接添加
else{
data['createtime'] = new Date().getTime();
data['updatetime'] = new Date().getTime();
res = store.add(data);
res.onerror = function(){
reject(
rJson(0, e, '查询出错了~')
);
}
res.onsuccess = function(){
resolve(
rJson(1, null, '保存成功~')
)
}
}
//if 2 end
}
//索引 End
}
//if end
});
}
/**
* 通过ID删除学员信息
*/
export const deleteStudentById = id => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
//删除指定信息
let res = store.delete(id);
res.onerror = function(e){
reject(
rJson(0, e, '操作出错了~')
);
}
res.onsuccess = function(){
resolve(
rJson(1, null, '删除成功~')
)
}
});
}
/**
* 通过ID删除多条学员信息
*/
export const deleteStudentByIds = ids => {
return new Promise((resolve, reject) => {
if(Array.isArray(ids)){
//打开游标
let {store} = openTransactionIndex(storeName, undefined, CONST_READ.READWRITE);
//打开游标
let cursor = store.openCursor();
cursor.onerror = function(e){
reject(
rJson(0, e, '操作出错了~')
);
}
cursor.onsuccess = function(e){
let result = e.target.result;
if(result){
if(ids.includes(result.key)){
result.delete();
}
result.continue();
}else{
resolve(
rJson(1, null, '删除成功~')
)
}
}
}else{
reject(
rJson(0, e, '请传入数组形式ID数据~')
);
}
//end
});
}
5.2 api接口
api/index.js文件中新增学员相关接口,代码如下:
import {
loadStudentAllList,
toggleStudent,
getStudentInfoById,
deleteStudentById,
deleteStudentByIds
} from '@/db/model/student'
/**
* 获取学员列表数据
*/
export const getStudentList = name => {
return loadStudentAllList(name);
}
/**
* 通过ID获取学员信息
*/
export const loadStudentById = id => {
return getStudentInfoById(id);
}
/**
* 添加 或 修改学员数据
*/
export const toggleStudentInfo = params => {
return toggleStudent(params);
}
/**
* 通过ID删除指定学员信息
*/
export const deleteStudentInfoById = id => {
return deleteStudentById(id);
}
/**
* 删除选中的学员信息
*/
export const deleteStudentInfoByIds = ids => {
return deleteStudentByIds(ids);
}
5.3 新增页面
在components/StudentDialog/index.vue中添加新增页面,html代码如下:
<template>
<el-dialog :title="uid!=0?'编辑':'新增'" :visible="visible" @close="closeEvent" width="420px" class="dialog-wrap">
<el-form :model="form" :rules="rules" status-icon ref="ruleForm">
<el-form-item label="学员姓名" :label-width="formLabelWidth" required prop="name">
<el-input v-model="form.name" autocomplete="off" size="small"></el-input>
</el-form-item>
<el-form-item label="户籍" :label-width="formLabelWidth" required prop="registration">
<el-input v-model="form.registration" autocomplete="off" size="small"></el-input>
</el-form-item>
<el-form-item label="手机号" :label-width="formLabelWidth" required prop="phone">
<el-input v-model="form.phone" autocomplete="off" size="small"></el-input>
</el-form-item>
<el-form-item label="年级" :label-width="formLabelWidth" prop="gid">
<el-select v-model="form.gid" placeholder="请选择" @change="gradeChange">
<el-option
v-for="item in gradeOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="班级" :label-width="formLabelWidth" prop="cid">
<el-select v-model="form.cid" placeholder="请选择">
<el-option
v-for="item in classOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="居住地址" :label-width="formLabelWidth" required prop="address">
<el-input v-model="form.address" autocomplete="off" size="small"></el-input>
</el-form-item>
<el-form-item label="出生日期" :label-width="formLabelWidth" required prop="birthday">
<el-date-picker v-model="form.birthday" value-format="yyyy-MM-dd" type="date" placeholder="选择日期"></el-date-picker>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button size="small" @click="closeEvent">取 消</el-button>
<el-button size="small" type="primary" @click="submitForm">保 存</el-button>
</div>
</el-dialog>
</template>
js代码如下:
<script>
import { toggleStudentInfo, loadStudentById, gradeAllList, getClassByKey } from '@/api'
import { formatDate } from '@/utils/utils'
export default {
props: {
//用户ID
uid: {
type: Number,
default: () => 0
},
visible: {
type: Boolean,
default: () => false
}
},
data(){
return {
formLabelWidth: '80px',
gradeOptions: [],
classOptions: [],
dateValue: "",
form: {
name: "",
registration: "",
phone: "",
gid: "",
cid: "",
address: "",
birthday: ""
},
rules: {
name: [
{ required: true, message: '请输入学员姓名', trigger: 'blur' },
{ required: true, message: '请输入学员姓名', trigger: 'change' },
],
registration: [
{ required: true, message: '请输入户籍', trigger: 'blur' },
{ required: true, message: '请输入户籍', trigger: 'change' },
],
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{ required: true, message: '请输入手机号', trigger: 'change' },
{ tel: true, message: '请输入手机号', trigger: 'blur' },
{ tel: true, message: '请输入手机号', trigger: 'change' },
],
gid: [
{ required: true, message: '请选择年级', trigger: 'change' },
],
cid: [
{ required: true, message: '请选择班级', trigger: 'change' },
],
address: [
{ required: true, message: '请输入现居住地址', trigger: 'blur' },
{ required: true, message: '请输入现居住地址', trigger: 'change' },
],
birthday: [
{ required: true, message: '请选择出生日期', trigger: 'blur' },
{ required: true, message: '请选择出生日期', trigger: 'change' },
{ date: true, message: '请选择出生日期', trigger: 'blur' },
{ date: true, message: '请选择出生日期', trigger: 'change' },
]
}
}
},
watch: {
uid(){
if(this.uid!=0){
this.updateStudentInfo();
}
}
},
created() {
this.updateGradeInfo();
},
methods: {
/**
* 获取年级信息
*/
updateGradeInfo(){
gradeAllList().then(res => {
if(res.code==1){
this.gradeOptions = res.data.map(item => {
return {
label: item.name,
value: item.id
};
})
}
}).catch(e => {
console.error(e);
})
},
/**
* 获取班级信息
*/
updateClassInfo(){
getClassByKey(this.form.gid).then(res => {
if(res.code==1){
this.classOptions = res.data.map(item => {
return {
label: item.name,
value: item.id
};
})
}
// console.log('res', res);
}).catch(e => {
console.error(e);
})
},
/**
* 年级发生变化
*/
gradeChange(){
this.form.cid = "";
this.updateClassInfo();
},
/**
* 获取班级
*/
updateStudentInfo(){
loadStudentById(this.uid).then(res => {
console.log(res)
if(res.code==1){
let data = res.data,
tmpData = {
name: res.data['name'],
registration: res.data['registration'],
phone: res.data['phone'],
// gid: "",
// cid: "",
address: res.data['address'],
birthday: res.data['birthday']
};
if(data['gid']){
tmpData['gid'] = data.gid;
}
if(data['cid']){
tmpData['cid'] = data.cid;
}
this.form = tmpData;
if(data['gid']){
this.updateClassInfo();
}
}
// console.log(res);
}).catch(e => {
console.error(e);
})
},
/**
* 获取保存数据
*/
getParams(){
let { name, registration, phone, address, birthday, gid, cid } = this.form;
return {
name, registration, phone, address, birthday, gid, cid
}
},
/**
* 添加班级信息
*/
addUserInfo(){
let param = this.getParams();
toggleStudentInfo(param).then(res => {
if(res.code==1){
this.$message.success('保存成功');
this.$emit('saveChange', {});
}
// console.log('success', res)
}).catch(e => {
this.$message.success(e.msg);
});
},
/**
* 编辑班级信息
*/
editUserInfo(){
let param = this.getParams();
param['id'] = this.uid;
toggleStudentInfo(param).then(res => {
if(res.code==1){
this.$message.success('保存成功');
this.$emit('saveChange', {});
}
// console.log('success', res)
}).catch(e => {
this.$message.success(e.msg);
});
},
/**
* 提交表单
*/
submitForm(){
// console.log(this.form)
this.$refs['ruleForm'].validate((valid) => {
if(valid){
//新增班级
if(this.uid==0){
this.addUserInfo();
}
//编辑班级
else{
this.editUserInfo();
}
}else{
return false;
}
});
},
/**
* 关闭事件
*/
closeEvent(){
this.$refs['ruleForm'].resetFields();
this.$emit('closeChange', {});
},
}
}
</script>
界面如下:
这里需要注意的是,为新增功能时,先加载年级数据列表,这部分接口是在之前年级功能实现就已经定义了,直接调用即可;当年级数据变化选中即,通过年级ID查询到对应的班级列表数据即可,这块接口也是在api/index.js中定义过的。
当为编辑功能时,获取到详情数据需判断年级ID是否存在,如果存在则需要通过年级ID查询 出对应班级数据列表。
5.4 列表页面
在pages/student/index.vue中添加列表页面,html代码如下:
<template>
<div class="index-wrap">
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>学员列表</el-breadcrumb-item>
</el-breadcrumb>
<br /><br />
<div class="filter-wrap">
<div class="item left">
<el-form :inline="true" class="demo-form-inline">
<el-form-item label="学员姓名">
<el-input size="small" placeholder="请输入学员姓名" v-model="keyword"></el-input>
</el-form-item>
<el-form-item>
<el-button size="small" type="primary" @click="updateList">查询</el-button>
</el-form-item>
</el-form>
</div>
<div class="item right">
<el-form :inline="true" class="demo-form-inline">
<el-form-item>
<el-button size="small" type="primary" @click="showAddDialog">新增</el-button>
<el-button size="small" type="info" @click="deleteSelectedStudent">删除</el-button>
</el-form-item>
</el-form>
</div>
</div>
<div class="table-wrap">
<el-table
@selection-change="selectionChange"
:data="tableList"
style="width: 100%">
<el-table-column type="selection" label="选择" width="50"> </el-table-column>
<el-table-column prop="name" label="学员姓名"></el-table-column>
<el-table-column prop="registration" label="户籍"></el-table-column>
<el-table-column prop="address" label="居住地址"></el-table-column>
<el-table-column prop="classify" label="班级"></el-table-column>
<el-table-column prop="age" label="年龄" width="80">
<template slot-scope="scope">
<span>{{scope.row.birthday | filterAge}}</span>
</template>
</el-table-column>
<el-table-column prop="createtime" label="创建日期" width="160"></el-table-column>
<el-table-column prop="updatetime" label="更新日期" width="160"></el-table-column>
<el-table-column label="操作" width="150">
<template slot-scope="scope">
<el-button type="primary" size="mini" icon="el-icon-edit" circle @click="editEvent(scope.row.id)"></el-button>
<el-button type="danger" size="mini" icon="el-icon-delete" circle @click="deleteEvent(scope.row.id)"></el-button>
</template>
</el-table-column>
</el-table>
</div>
<StudentDialog :visible="isShowDialog" :uid="selectId" @closeChange="closeDialog" @saveChange="saveChange"></StudentDialog>
</div>
</template>
js代码部分:
<script>
import StudentDialog from '@/components/StudentDialog'
import { getStudentList, deleteStudentInfoById, deleteStudentInfoByIds } from '@/api'
import { formatDate } from '@/utils/utils'
export default {
data () {
return {
//选中ID
selectId: 0,
//搜索关键词
keyword: "",
/**
* 是否显示弹框
*/
isShowDialog: false,
/**
* 列表数据
*/
tableList: [],
/**
* 选择项
*/
multipleSelection: []
}
},
filters: {
filterAge(val){
let current = new Date(),
bDate = new Date(val);
return current.getFullYear() - bDate.getFullYear();
}
},
components: {
StudentDialog
},
created() {
this.updateList();
},
methods: {
/**
* 获取列表数据
*/
updateList(){
getStudentList(this.keyword).then(res => {
// console.log(res);
if(res.code==1){
this.tableList = res.data.map(item => {
item['createtime'] = formatDate(item.createtime);
item['updatetime'] = formatDate(item.updatetime);
return item;
});
}
}).catch(e => {
console.error(e);
})
},
/**
* 显示弹框事件
*/
showAddDialog(){
this.isShowDialog = true;
},
/**
* 关闭弹框
*/
closeDialog(){
this.selectId = 0;
this.isShowDialog = false;
},
/**
* 保存成功
*/
saveChange(){
this.updateList();
this.isShowDialog = false;
},
/**
* 编辑学员信息
* @param {Object} id
*/
editEvent(id){
this.selectId = id;
this.isShowDialog = true;
},
/**
* 删除学员信息
* @param {Object} id
*/
deleteEvent(id){
this.$confirm('确认要删除该学员信息吗?', '提示', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(res => {
deleteStudentInfoById(id).then(() => {
this.$message.success('删除成功!');
this.updateList();
}).catch(e => {
this.$message.error(e.msg);
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
/**
* check 选中项项值
* @param {Object} val
*/
selectionChange(val){
this.multipleSelection = val;
},
/**
* 删除选中的学员信息
*/
deleteSelectedStudent(){
if(this.multipleSelection.length==0){
this.$message({
type: 'info',
message: '请选择删除项'
});
return;
}
this.$confirm('确认要删除选中的学员信息吗?', '提示', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
}).then(res => {
deleteStudentInfoByIds(this.multipleSelection.map(item => item.id)).then(() => {
this.$message.success('删除成功!');
this.updateList();
}).catch(e => {
this.$message.error(e.msg);
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
//end
}
}
</script>
界面效果如下:
5.5 关联数据查询
这里出现同样的问题,关键班级的信息未显示出来,和班级中查询关联数据一样,以同样方式即可。
第一步:打开db\model\classify.js文件,添加getClassByIdsCursor()函数,代码如下:
/**
* 通过游标获取对应数据集
*/
export const getClassByIdsCursor = ids => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName);
//通过ID获取数据
let cursor = store.openCursor(),
reData = {};
cursor.onerror = function(e){
reject();
}
cursor.onsuccess = function(e){
let result = e.target.result;
if(result){
if(ids.includes(result.value.id)){
reData[result.value.id] = result.value;
}
result.continue();
}else{
resolve(reData);
}
}
//end
});
}
第二步:打开db\model\student.js文件,修改loadStudentAllList()函数,代码如下:
/**
* 获取 学员列表
*/
export const loadStudentAllList = name => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName);
//获取所有数据
let alls = store.getAll();
alls.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
alls.onsuccess = function(e){
let result = e.target.result;
if(result){
let rData = result;
if(name){
rData = result.filter(item => item.name.includes(name));
}
getClassByIdsCursor(rData.filter(item => item.cid).map(item => item.cid)).then(res => {
rData = rData.map(item => {
if('undefined'!==typeof res[item.cid]){
item['classify'] = res[item.cid]['name'];
}
return item;
})
resolve(
rJson(1, rData, '获取成功~')
)
}).catch(e => {
reject(
rJson(0, e, '查询出错了~')
)
});
}else{
reject(
rJson(0, null, '未查询到数据~')
)
}
}
});
}
现在列表页面效果如下:
六、分页功能
这里我们以学员列表为例,添加分页查询功能。注意的是,其他页面列表查询已在各关键页面中使用,为了避免影响别的功能,建议新建分页查询 函数。
6.1 分页功能函数
首先打开src/utils/utils.js文件,添加分页功能函数,代码如下:
/**
* 生成分页数据
*/
export const genderPage = (data, param) => {
//判断分页数据是否存在,否则赋值默认参数
param = param && 'undefined'!==typeof param['page'] && 'undefined'!==typeof param['pageSize'] ? param : {
page: 1,
pageSize: 10
}
let newData = data.map(item => item),
start = (param.page - 1) * param.pageSize,
end = newData.length - start < param.pageSize ? newData.length : start + param.pageSize;
return newData.slice(start, end);
}
6.2 增加分页查询功能
打开db/model/student.js,添加分页查询函数loadStudentPage(),代码如下:
import { DBIsLoadSuccess, openTransactionIndex, CONST_READ } from '@/db'
import { rJson, genderPage } from '@/utils/utils'
import { getClassByIdsCursor } from './classify.js'
let storeName = 'student';
/**
* 获取 学员列表 - 分页模式
* @param name 查询关键词
* @param param 分页参数
*/
export const loadStudentPage = (name, param) => {
return new Promise((resolve, reject) => {
//打开游标
let {store} = openTransactionIndex(storeName);
//获取所有数据
let alls = store.getAll();
alls.onerror = function(e){
reject(
rJson(0, e, '查询出错了~')
);
}
alls.onsuccess = function(e){
let result = e.target.result;
if(result){
let rData = result;
if(name){
rData = result.filter(item => item.name.includes(name));
}
//查询班级关联数据
getClassByIdsCursor(rData.filter(item => item.cid).map(item => item.cid)).then(res => {
rData = rData.map(item => {
if('undefined'!==typeof res[item.cid]){
item['classify'] = res[item.cid]['name'];
}
return item;
})
//通过genderPageData函数进行分页处理
resolve(
rJson(1, {
list: genderPage(rData, param),
total: rData.length
}, '获取成功~')
)
}).catch(e => {
reject(
rJson(0, e, '查询出错了~')
)
});
}else{
reject(
rJson(0, null, '未查询到数据~')
)
}
}
});
}
6.3 api接口
打开api/index.js,添加分页查询接口函数,代码如下:
import {
loadStudentPage
} from '@/db/model/student'
/**
* 获取学员列表数据 - 分页模式
*/
export const getStudentPageList = (name, param) => {
return loadStudentPage(name, param);
}
6.4 添加分页代码
html部分,在列表下添加分页代码,代码如下:
<div class="table-wrap">
...
<el-pagination
background
layout="prev, pager, next"
@current-change="currentChange"
:current-page="page"
:page-size="pageSize"
:total="pageTotal">
</el-pagination>
</div>
js部分,引入getStudentPageList接口函数,在data中添加分页参数,增加分页切换事件,代码如下:
import StudentDialog from '@/components/StudentDialog'
import { getStudentList, getStudentPageList, deleteStudentInfoById, deleteStudentInfoByIds } from '@/api'
import { formatDate } from '@/utils/utils'
export default {
data () {
return {
//...
//分页参数
page: 1,
pageSize: 5,
pageTotal: 0
}
},
filters: {
filterAge(val){
let current = new Date(),
bDate = new Date(val);
return current.getFullYear() - bDate.getFullYear();
}
},
components: {
StudentDialog
},
created() {
this.updateList();
},
methods: {
/**
* 当前页发生改变
*/
currentChange(page){
this.page = page;
this.updateList();
}
}
6.5 修改列表查询函数
由于分页查询功能中需要返回数据总量,则原来返回结果结构发生变化,所以updateList()函数需要稍微调整下,代码如下:
methods: {
/**
* 获取列表数据
*/
updateList(){
getStudentPageList(this.keyword, {
page: this.page,
pageSize: this.pageSize
}).then(res => {
if(res.code==1){
this.pageTotal = res.data['total'];
this.tableList = res.data['list'].map(item => {
item['createtime'] = formatDate(item.createtime);
item['updatetime'] = formatDate(item.updatetime);
return item;
});
}
}).catch(e => {
console.error(e);
})
},
//...
}
此时页面效果如下:
到此为止,该系统开发则已经完结了,有兴趣的朋友可以再升级和优化下。
由于近期工作原因,不是每天都能抽出时间开发,所以有些不太连贯,望见谅。此篇对增删改查也没作太多细讲,因为都差不多,大家可以拷贝代码到本地运行自行研究。