持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第28天,点击查看活动详情
接CMS数据可视化03
一个项目的剩下内容,主要是ajax内容
成绩管理
获取成绩并展示
这个功能有对应的接口,而且得到的数据不需要处理,直接可以使用。认真阅读接口文档。
// -------------- 获取分数,展示列表 ------------
function renderScore() {
axios.get('/score/list').then(({ data: res }) => {
// console.log(res);
let { code, data } = res;
if (code === 0) {
let arr = [];
for (let key in data) {
arr.push(`
<tr>
<th scope="row">${key}</th>
<td>${data[key].name}</td>
<td class="score">${data[key].score[0]}</td>
<td class="score">${data[key].score[1]}</td>
<td class="score">${data[key].score[2]}</td>
<td class="score">${data[key].score[3]}</td>
<td class="score">${data[key].score[4]}</td>
</tr>
`);
}
$('tbody').html(arr.join(''))
}
})
}
renderScore();
可编辑的表格效果
添加和修改成绩,并没有使用弹出层等效果。而是采用可编辑的表格。
可编辑的表格,需要用到的技术就是DOM操作,没有其他。
思路如下:
- 点击单元格
td.score,获取单元格的值。 - 创建input
- 设置input的样式和td的样式一致,或者自行修改样式。
- 将 单元格的值 设置为 input 的 value
- 将 input 放入 td 中,并获取焦点
后续补充,输入框中按回车,表示确定,失去焦点表示取消
- 给input注册 keyup 和 blur 事件。
完整代码:
// 可编辑的表格
$('tbody').on('click', '.score', function () {
let td = $(this);
if (td.children().length > 0) return; // 判断如果已经有input了,就不要在重复添加input了
let text = td.text(); // 保存td中的分数
td.html(''); // 设置td的内容为空
let input = $('<input />'); // 创建input
input // 设置input的样式
.css('color', td.css('color')) // 设置input的color和td的color相同
.css('background-color', td.css('background-color'))
.css('font-size', td.css('font-size'))
.css('width', '100%')
.css('height', '100%')
.css('outline', 'none')
.css('border', 'none')
.val(text) // 将原来td中的值,设置为input的value
.appendTo(td) // 将input添加到td中
.focus(); // 让input获取焦点,即有光标闪烁效果
// 为input注册 keyup 事件
input.on('keyup', function (e) {
if (e.keyCode === 13) {
// console.log('按下回车键,这里调用接口,修改或录入成绩');
}
})
// 为input注册blur事件
input.on('blur', function () {
td.html(text); // 失去焦点后,将原来td的值设置回去
})
})
修改或录入成绩
接口分析:
- 需要学员id 参数
- 需要batch次数 参数
- 需要score成绩 参数
所以,在循环遍历数据时,将需要的 学员id 和 batch次数,用自定义属性 data-xx 存储。
arr.push(`
<tr>
<th scope="row">${key}</th>
<td>${data[key].name}</td>
<td data-batch="1" data-id="${key}" class="score">${data[key].score[0]}</td>
<td data-batch="2" data-id="${key}" class="score">${data[key].score[1]}</td>
<td data-batch="3" data-id="${key}" class="score">${data[key].score[2]}</td>
<td data-batch="4" data-id="${key}" class="score">${data[key].score[3]}</td>
<td data-batch="5" data-id="${key}" class="score">${data[key].score[4]}</td>
</tr>
当按下回车键后,获取接口所需参数,调用接口发送请求,进行成绩的修改和录入
input.on('keyup', function (e) {
if (e.keyCode === 13) {
// console.log('按下回车键,这里调用接口,修改或录入成绩');
let score = $(this).val();
if (isNaN(score) || score < 0 || score > 100) {
return toastr.warning('请输入0~100之间的数字');
}
let stu_id = td.data('id');
let batch = td.data('batch');
// console.log(score, stu_id, batch);
axios.post('/score/entry', { score, stu_id, batch }).then(({ data: res }) => {
if (res.code === 0) {
toastr.success(res.message);
td.html(score) // 修改成功后,将新的成绩 放到 td 中
}
})
}
})
学员管理
获取数据展示
这也是一个常规操作,按照接口文档获取数据,然后循环遍历到表格中即可。
// 获取学员数据
function renderStudent() {
axios.get('/student/list').then(({ data: res }) => {
// console.log(res);
if (res.code === 0) {
let arr = [];
res.data.forEach(item => {
arr.push(`
<tr>
<th scope="row">${item.id}</th>
<td>${item.name}</td>
<td>${item.age}</td>
<td>${item.sex}</td>
<td>${item.group}</td>
<td>${item.phone}</td>
<td>${item.salary}</td>
<td>${item.truesalary}</td>
<td>${item.province}${item.city}${item.county}</td>
<td>
<button type="button" class="btn btn-primary btn-sm update">修改</button>
<button type="button" class="btn btn-danger btn-sm del">删除</button>
</td>
</tr>
`);
});
$('tbody').html(arr.join(''))
}
})
}
renderStudent();
添加 -- 分析
-
添加使用了 bootstrap4 的模态框(弹出框),这个只需按 bootstrap 的语法写即可。
-
表单中有“省市县”联动效果。当然也有对应的接口。
- 开始时,先获取所有的省,放到第一个下拉框中
- 当“省”切换的时候,获取对应的市,并放入第二个下拉框中。
- 当“市”切换的时候,获取对应的县,并放入第三个下拉框中
-
需要有表单验证,这个安装表单验证插件的语法写即可。
-
一切准备就绪,提交表单数据,完成添加即可。
添加 -- 省市县联动
// --------------------- 获取省 ---------------------
axios.get('/geo/province').then(({ data: res }) => {
// console.log(res);
let arr = ['<option selected value="">--省--</option>'];
res.forEach(item => {
arr.push(`<option value="${item}">${item}</option>`)
});
$('select[name=province]').html(arr.join(''))
})
// --------------------- 省切换的时候,选择市 ---------------------
$('select[name=province]').on('change', function () {
// 重置县
$('select[name=county]').html(`<option selected value="">--县--</option>`);
let pname = $(this).val();
axios.get('/geo/city', { params: { pname } }).then(({ data: res }) => {
// console.log(res);
let arr = ['<option selected value="">--市--</option>'];
res.forEach(item => {
arr.push(`<option value="${item}">${item}</option>`)
});
$('select[name=city]').html(arr.join(''))
})
})
// --------------------- 市切换的时候,选择县 ---------------------
$('select[name=city]').on('change', function () {
let pname = $(this).parents('.col-sm-3').prev().find('select').val();
let cname = $(this).val();
axios.get('/geo/county', { params: { pname, cname } }).then(({ data: res }) => {
// console.log(res);
let arr = ['<option selected value="">--县--</option>'];
res.forEach(item => {
arr.push(`<option value="${item}">${item}</option>`)
});
$('select[name=county]').html(arr.join(''))
})
})
添加 -- 表单验证
function student() {
return {
fields: {
name: {
validators: {
notEmpty: {
message: '姓名不能为空',
},
stringLength: {
min: 2,
max: 10,
message: '姓名长度2~10位'
}
}
},
age: {
validators: {
notEmpty: {
message: '年龄不能为空',
},
greaterThan: {
value: 18,
message: '年龄不能小于18岁'
},
lessThan: {
value: 60,
message: '年龄不能超过60岁'
}
}
},
sex: {
validators: {
choice: {
min: 1,
max: 1,
message: '请选择性别'
}
}
},
group: {
validators: {
notEmpty: {
message: '组号不能为空',
},
regexp: {
regexp: /^\d{1,2}$/,
message: '请选择有效的组号'
}
}
},
phone: {
validators: {
notEmpty: {
message: '手机号不能为空',
},
regexp: {
regexp: /^1\d{10}$/,
message: '请填写有效的手机号'
}
}
},
salary: {
validators: {
notEmpty: {
message: '实际薪资不能为空',
},
greaterThan: {
value: 800,
message: '期望薪资不能低于800'
},
lessThan: {
value: 100000,
message: '期望薪资不能高于100000'
}
}
},
truesalary: {
validators: {
notEmpty: {
message: '实际薪资不能为空',
},
greaterThan: {
value: 800,
message: '实际薪资不能低于800'
},
lessThan: {
value: 100000,
message: '实际薪资不能高于100000'
}
}
},
province: {
validators: {
notEmpty: {
message: '省份必填',
},
}
},
city: {
validators: {
notEmpty: {
message: '市必填',
},
}
},
county: {
validators: {
notEmpty: {
message: '县必填',
},
}
},
}
}
}
添加 -- 完成添加
// 添加学生
$('.add-form').bootstrapValidator(student()).on('success.form.bv', function (e) {
e.preventDefault();
//提交逻辑
// console.log(222);
let data = $(this).serialize();
// console.log(data);
axios.post('/student/add', data).then(({ data: res }) => {
// console.log(res);
if (res.code === 0) {
toastr.success(res.message);
renderStudent();
$('#addModal').modal('hide') // 这个是关闭模态框(弹出框)的意思
}
})
});
修改 -- 分析
-
修改中,也会用到省市县联动。但是不用再写代码了,前面添加的时候已经写过了。
-
修改时,表单(每个输入框)不能为空,必须设置好默认的value值,这个操作叫做数据回填。所有的修改操作都需要数据回填
- 点击 修改 按钮
- 发送请求,获取该学员的信息。
- 得到数据后,设置每个输入框的value值。下拉框和单项按钮需设置选中状态。
-
修改接口,需要学员id,所以在修改表单中,加入
<input type="hidden" name="id" /> -
最后,按照接口文档,完成修改即可。
修改 -- 数据回填
遍历数据时,用 data-id 属性,存储该学员的 id
arr.push(`
<tr>
<th scope="row">${item.id}</th>
<td>${item.name}</td>
<td>${item.age}</td>
<td>${item.sex}</td>
<td>${item.group}</td>
<td>${item.phone}</td>
<td>${item.salary}</td>
<td>${item.truesalary}</td>
<td>${item.province}${item.city}${item.county}</td>
<td>
+ <button data-id="${item.id}" type="button" class="btn btn-primary btn-sm update">修改</button>
<button type="button" class="btn btn-danger btn-sm del">删除</button>
</td>
</tr>
`);
JS代码如下:
// 修改学员 --- 数据回填
$('tbody').on('click', '.update', function () {
let id = $(this).data('id');
axios.get('/student/one', { params: { id } }).then(({ data: res }) => {
if (res.code === 0) {
// console.log(res.data);
let { name, age, sex, group, phone, id, salary, truesalary, province, city, county } = res.data;
$('#updateModal input[name=id]').val(id);
$('#updateModal input[name=name]').val(name);
$('#updateModal input[name=age]').val(age);
$('#updateModal input[name=sex][value=' + sex + ']').prop('checked', true);
$('#updateModal input[name=phone]').val(phone);
$('#updateModal input[name=salary]').val(salary);
$('#updateModal input[name=truesalary]').val(truesalary);
$('#updateModal select[name=group]').children('[value=' + group + ']').prop('selected', true);
$('#updateModal select[name=province]').children('[value=' + province + ']').prop('selected', true);
$('#updateModal select[name=city]').html(`<option value="${city}">${city}</option>`);
$('#updateModal select[name=county]').html(`<option value="${county}">${county}</option>`);
$('#updateModal').modal('show'); // 这行的意思是让模态框显示
}
})
})
修改 -- 完成修改
// 修改学员 --- 确认修改
$('.update-form').bootstrapValidator(student()).on('success.form.bv', function (e) {
e.preventDefault();
//提交逻辑
// console.log(222);
let data = $(this).serialize();
// console.log(data);
axios.put('/student/update', data).then(({ data: res }) => {
// console.log(res);
if (res.code === 0) {
toastr.success(res.message);
renderStudent();
$('#updateModal').modal('hide')
}
})
});
删除操作
遍历数据时,用 data-id 属性,存储该学员的 id
arr.push(`
<tr>
<th scope="row">${item.id}</th>
<td>${item.name}</td>
<td>${item.age}</td>
<td>${item.sex}</td>
<td>${item.group}</td>
<td>${item.phone}</td>
<td>${item.salary}</td>
<td>${item.truesalary}</td>
<td>${item.province}${item.city}${item.county}</td>
<td>
<button data-id="${item.id}" type="button" class="btn btn-primary btn-sm update">修改</button>
+ <button data-id="${item.id}" type="button" class="btn btn-danger btn-sm del">删除</button>
</td>
</tr>
`);
JS代码如下:
// 删除学员
$('tbody').on('click', '.del', function () {
if (!confirm('你确定要删除吗?')) return;
let id = $(this).data('id');
axios.delete('/student/delete', { params: { id } }).then(({ data: res }) => {
if (res.code === 0) toastr.success(res.message); renderStudent();
})
})
最后是原图