• urls.py

urlpatterns = [
url('^asset.html$', views.AssetView.as_view()),
url('^asset-json.html$', views.AssetJsonView.as_view()),
]
  • views.py

# CBV方式
class AssetView(View):
def get(self,request,*args,**kwargs):
# 数据库中获取数据
return render(request, 'asset.html') class AssetJsonView(View):
def get(self,request,*args,**kwargs):
table_config = [
{
'q': None,
'title': '选项',
'display': True,
'text': {'content':'<input type="checkbox" />','kwargs': {}},
'attrs': {},
},
{
'q':'id',
'title':'ID',
'display':False,
'text':{},
'attrs':{},
},
{
'q': 'asset_type_id',
'title': '资产类型',
'display': True, # 是否显示
'text': {'content': '{n}', 'kwargs': {'n': '@@asset_type_choices', }},
'attrs': {},
},
{ # 'edit-type': 'select'可编辑时变成下拉框
'q': 'status_id',
'title': '状态',
'display': True, # 是否显示
'text': {'content': '{n}', 'kwargs': {'n': '@@status_choices',}},# 双@表示找选项里对应的内容
'attrs': {'name':'status_id','origin':'@status_id','edit-enable': 'true', 'edit-type': 'select','global-name':'status_choices'},
},
{
'q': 'idc__id',
'title': '机房ID',
'display': False,
'text': {},
'attrs': {},
},
{
'q': 'idc__name', # 一对多跨表操作
'title': '机房',
'display': True, # 是否显示
'text': {'content': '{n}', 'kwargs': {'n': '@idc__name', }},# 一个@表示取数据库中的信息
'attrs': {'name':'idc_id','origin':'@idc__id','edit-enable': 'true', 'edit-type': 'select','global-name':'idc_choices'},
},
{
'q': 'cabinet_num',
'title': '机柜号',
'display': True,
'text': {'content':'{n}','kwargs':{'n':'@cabinet_num'}},
'attrs': {'name':'cabinet_num','origin':'@cabinet_num','edit-enable': 'true', 'edit-type': 'input'},
},
{
'q': 'cabinet_order',
'title': '机柜位置',
'display': True,
'text': {'content': '{n}', 'kwargs': {'n': '@cabinet_order'}},
'attrs': {},
},
{
'q': None, # 表示不去数据库取数据
'title': '操作',
'display': True,
'text': {'content': '<a href="/asset_detail-{m}.html">{n}</a>', 'kwargs': {'m':'@id','n':'详细'}},
'attrs': {},
},
]
q_list = []
for i in table_config:
if not i['q']:
continue
q_list.append(i['q'])
data_list = Asset.objects.all().values(*q_list)
data_list = list(data_list)
print(data_list) # [{'id': 1, 'cabinet_num': '12B', 'cabinet_order': '1'}]
result = {
'table_config':table_config,
'data_list':data_list,
'pager':'''
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
<li><a href="#">4</a></li>
<li><a href="#">5</a></li>
''',
'global_dict':{
'asset_type_choices': Asset.asset_type_choices, # json处理之后,元组会变成列表
'status_choices': Asset.status_choices,
'idc_choices': list(IDC.objects.values_list('id','name')),
},
}
return HttpResponse(json.dumps(result)) def put(self,request,*args,**kwargs):
# 没有request.post
content = request.body
val = json.loads(str(content,encoding='utf-8'))
ret = {'status':True}
return HttpResponse(json.dumps(ret))
  • html文件

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>后台管理</title>
{% load staticfiles %}
<link rel="stylesheet" href="{% static 'plugins/bootstrap/css/bootstrap.css' %}"/>
<link rel="stylesheet" href="{% static 'plugins/font-awesome/css/font-awesome.css' %}"/>
</head>
<body>
<div style="width: 1000px;margin: 0 auto;">
<h1>资产列表</h1>
<div class="btn-group" role="group" aria-label="...">
<button id="idCheckAll" type="button" class="btn btn-default">全选</button>
<button id="idReverseAll" type="button" class="btn btn-default">反选</button>
<button id="idCancelAll" type="button" class="btn btn-default">取消</button>
<button id="idEditMode" type="button" class="btn btn-default">进入编辑模式</button>
<button type="button" class="btn btn-default">批量删除</button>
<a id="idAdd" href="asset_add.html" class="btn btn-default">添加</a>
<button id="idSave" type="button" class="btn btn-default">保存</button>
</div>
<table class="table table-bordered">
<thead id="table_th">
</thead>
<tbody id="table_tb">
</tbody>
</table>
<ul id="idPagination" class="pagination">
</ul>
</div>
<script src="{% static 'js/jquery-3.3.1.js' %}"></script>
<script src="{% static 'js/nbList.js' %}"></script>
<script>
$(function () {
$.NB('/asset-json.html');
});
</script>
</body>
</html>
  • 公共JS组件:主要是调用扩展方法NB

(function () {
var requestUrl = null; //绑定分页事件
function bindChangePager(){
$('#idPagination').on('click','a',function () {
var pageNum = $(this).text();
init(pageNum);
})
} //保存
function bindSave() {
$('#idSave').click(function () {
//找到有hasEdit属性的tr标签
var postList = [];
$('#table_tb').find('tr[has-edit="true"]').each(function () {
//$(this)=tr
var temp = {
/*
'id':1,
'status':1,
'order':12,*/
};
temp['id'] = $(this).attr('row-id');
$(this).children('[edit-enable="true"]').each(function () {
//$(this)=td
var name = $(this).attr('name'); //'name':'cabinet_num'
var origin = $(this).attr('origin');
var newVal = $(this).attr('new-val');
if(origin != newVal){
temp[name] = newVal; //'idc_id':2 新的select的value
}
});
postList.push(temp);
});
$.ajax({
url:requestUrl,
type:'PUT',
data:{'post_list':JSON.stringify(postList)},
dataType: 'JSON',
success:function (arg) {
if(arg.status){
init(1); //初始化到第一页
}else{
alert(arg.error);
}
}
})
})
} //全选
function bindCheckAll() {
$('#idCheckAll').click(function () {
$('#table_tb').find(':checkbox').each(function () {
if($('#idEditMode').hasClass('btn-warning')){
if($(this).prop('checked')){
//如果当前行已经进入了编辑模式
}else{
trIntoEditMode($currentTr = $(this).parent().parent());
$(this).prop('checked',true);
}
}else{
$(this).prop('checked',true);
}
})
})
} //取消
function bindCancelAll() {
$('#idCancelAll').click(function () {
$('#table_tb').find(':checked').each(function () {
if($('#idEditMode').hasClass('btn-warning')){
$(this).prop('checked',false);
//取消选中,并退出编辑模式
trOutEditMode($(this).parent().parent());
}else{
$(this).prop('checked',false);
}
});
})
} //反选
function bindReverseAll() {
$('#idReverseAll').click(function () {
$('#table_tb').find(':checkbox').each(function () {
if($('#idEditMode').hasClass('btn-warning')){
if($(this).prop('checked')){
//如果已经进入编辑模式,选中的要取消,再退出编辑
$(this).prop('checked',false);
trOutEditMode($(this).parent().parent());
}else{
//如果已经进入编辑模式,未选中的要选中,再进入编辑
$(this).prop('checked',true);
trIntoEditMode($(this).parent().parent());
}
}else{
if($(this).prop('checked')){
$(this).prop('checked',false);
}else{
$(this).prop('checked',true);
}
}
})
})
} //点击进入或退出编辑模式
function bindEditMode(){
$('#idEditMode').click(function () {
if($(this).hasClass('btn-warning')){
//退出编辑模式
$(this).removeClass('btn-warning');
$(this).text('进入编辑模式');
//找到所有选中的tr,进入编辑模式
$('#table_tb').find(':checked').each(function () {
var $currentTr = $(this).parent().parent();
trOutEditMode($currentTr);
})
}else{
//进入编辑模式
$(this).addClass('btn-warning');
$(this).text('退出编辑模式');
//找到所有选中的tr,退出编辑模式
$('#table_tb').find(':checked').each(function () {
var $currentTr = $(this).parent().parent();
trIntoEditMode($currentTr);
})
}
})
} //委托绑定:如果用ajax在页面上添加了一行数据,会自动绑定这个事件
function bindCheckbox(){
$('#table_tb').on('click',':checkbox',function () {
if($('#idEditMode').hasClass('btn-warning')){
var ck = $(this).prop('checked');
var $currentTr = $(this).parent().parent(); //变量前带$的表示为jQuery对象,只是自己看着方便
if(ck){
//选中状态,进入编辑,给tr加上背景色
trIntoEditMode($currentTr);
}else{
trOutEditMode($currentTr);
}
}
})
} //选中,进入编辑模式
function trIntoEditMode($tr){
$tr.addClass('success');
$tr.attr('has-edit','true'); // 只要进入过编辑状态的,都加上这个属性
$tr.children().each(function () {
//$(this)就是tr的每一个孩子td
var editEnable = $(this).attr('edit-enable'); //检查当前是否是可编辑模式
var editType = $(this).attr('edit-type');
if(editEnable == 'true'){
//可以进入编辑模式
if(editType == 'select'){
//生成下拉框
var globalName = $(this).attr('global-name'); //global-name = status_choices
var origin = $(this).attr('origin'); //
//生成select标签
var selectTag = document.createElement('select');
selectTag.className = 'form-control';
$.each(window[globalName],function (k1,v1) {
var optionTag = document.createElement('option');
optionTag.setAttribute('value',v1[0]);
optionTag.innerHTML = v1[1];
$(selectTag).append(optionTag);
});
$(selectTag).val(origin);
$(this).html(selectTag);
}else if(editType == 'input'){
//生成input框
var innerText = $(this).text();
var tag = document.createElement('input');
tag.className = 'form-control';
tag.style.width = '100%';
tag.value = innerText;
$(this).html(tag);
}
}
})
} //取消选中,退出编辑模式
function trOutEditMode($tr){
$tr.removeClass('success');
$tr.children().each(function () {
//$(this)就是tr的每一个孩子td
var editEnable = $(this).attr('edit-enable'); //检查当前是否可编辑
var editType = $(this).attr('edit-type');
if(editEnable == 'true'){
//如果是可编辑的
if(editType == 'select'){
//如果是select框
var $select = $(this).children().first(); //jQuery对象
var newId = $select.val(); //选中的option的id
var newText = $select[0].selectedOptions[0].innerHTML;//选中的option的text
$(this).html(newText); //用文本替换原来的select框
$(this).attr('new-val',newId); //设置新的value值
}else{
var inputVal = $(this).children().first().val(); //获取input的值
$(this).html(inputVal);
$(this).attr('new-val',inputVal);
}
}
})
} //自定义string方法,字符串格式化
String.prototype.format = function (kwargs) {
return this.replace(/\{(\w+)\}/g,function (km,m) {
return kwargs[m];
})
}; //初始化
function init(pager) {
$.ajax({
url:requestUrl,
type:'GET',
data:{pager:pager}, //把请求的页码告诉后台
dataType:'JSON',
success:function (result) {
initGlobalData(result.global_dict);
initHeader(result.table_config);
initBody(result.table_config,result.data_list);
initPager(result.pager);
}
})
} //初始化分页
function initPager(pager) {
$('#idPagination').html(pager);
} //初始化表头生成<tr><th>ID</th></tr>
var tr = document.createElement('tr');
function initHeader(table_config) {
$('#table_th').empty(); ////先清空所有的tr,再添加tr
$.each(table_config,function (k,item) {
//k是列表索引,item是字典
if(item.display){
th = document.createElement('th');
th.innerHTML=item.title;
$(tr).append(th);
}
});
console.log(tr);
$('#table_th').append(tr);
} //初始化tbody内容
function initBody(table_config,data_list) {
$('#table_tb').empty(); //先清空,再添加
$.each(data_list,function (k,row) {
//row={'id': 1, 'cabinet_num': '12B', 'cabinet_order': '1'}
var tr = document.createElement('tr');
tr.setAttribute('row-id',row['id']); //生成tr标签时,就把行ID传给它,日后更新时根据这个ID更新
$.each(table_config,function (i,colConfig) {
/*{
'q': 'cabinet_num',
'title': '机柜号',
'display': True,
'text': {'content':'{n}-{m}','kwargs':{'n':'机柜','m':'@xx'}},
'sttrs': {'edit-enable': 'true', 'edit-type': 'select'}
}*/
if(colConfig.display){
var td = document.createElement('td');
//table_config.text={'content': '{n}-{m}', 'kwargs': {'n': '机柜', 'm': '@xx'}},
//colConfig.q是数据库中的字段名
//生成td的文本信息
var kwargs = {};
$.each(colConfig.text.kwargs,function (key,value) {
if(value.substring(0,2) == '@@'){
//两个@@开头的,把选项ID转换成内容
var globalName = value.substring(2,value.length);//全局变量的名称
var currentId = row[colConfig.q]; //获取的数据库中存储的数字类型值
var t = getText(globalName,currentId); //根据ID去全局变量中找对应内容
kwargs[key] = t;
}else if(value[0]=='@'){
//以@开头的就只取@后面的字段的值
kwargs[key] = row[value.substring(1,value.length)];
}else {
kwargs[key] = value;
}
});
var temp = colConfig.text.content.format(kwargs);
td.innerHTML = temp;
//设置td的属性colConfig.attrs = {'origin':'@status_id','edit-enable': 'true', 'edit-type': 'select'},
$.each(colConfig.attrs,function (kk,vv) {
if(vv[0] == '@'){ //vv=@status_id
td.setAttribute(kk,row[vv.substring(1,vv.length)]);//origin=1
}else{
td.setAttribute(kk,vv);
}
});
tr.append(td);
}
});
$('#table_tb').append(tr);
});
} //设置全局变量,初始化下拉框里的选择项
function initGlobalData(global_dict) {
$.each(global_dict,function (k,v) {
//设置全局变量
window[k] = v;
})
} //根据ID获取全局变量里对应内容
var ret = null;
function getText(globalName,currentId) {
//globalName='asset_type_choices'
//currentId=1
$.each(window[globalName],function (k,item) {
if(currentId == item[0]){
ret = item[1];
return
}
});
return ret;
} //扩展方法
jQuery.extend({
'NB':function (url) {
requestUrl = url;
init();
bindEditMode();
bindCheckbox();
bindCheckAll();
bindCancelAll();
bindReverseAll();
bindSave();
bindChangePager();
},
'changePager':function (num) {
init(num);
}
});
})();

公共的JS组件-告别CURD的更多相关文章

  1. JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(三):两个Viewmodel搞定增删改查

    前言:之前博主分享过knockoutJS和BootstrapTable的一些基础用法,都是写基础应用,根本谈不上封装,仅仅是避免了html控件的取值和赋值,远远没有将MVVM的精妙展现出来.最近项目打 ...

  2. vue.js组件化开发实践

    前言 公司目前制作一个H5活动,特别是有一定统一结构的活动,都要码一个重复的轮子.后来接到一个基于模板的活动设计系统的需求,便有了下面的内容.借油开车. 组件化 需求一到,接就是怎么实现,技术选型自然 ...

  3. JS组件系列——封装自己的JS组件,你也可以

    前言:之前分享了那么多bootstrap组件的使用经验,这篇博主打算研究下JS组件的扩展和封装,我们来感受下JQuery为我们提供$.Extend的神奇,看看我们怎么自定义自己的组件,比如我们想扩展一 ...

  4. JS组件系列——封装自己的JS组件

    前言:之前分享了那么多bootstrap组件的使用经验,这篇博主打算研究下JS组件的扩展和封装,我们来感受下JQuery为我们提供$.Extend的神奇,看看我们怎么自定义自己的组件,比如我们想扩展一 ...

  5. VUE.JS组件化

    VUE.JS组件化 前言 公司目前制作一个H5活动,特别是有一定统一结构的活动,都要码一个重复的轮子.后来接到一个基于模板的活动设计系统的需求,便有了下面的内容.借油开车. 组件化 需求一到,接就是怎 ...

  6. JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(一)

    前言:出于某种原因,需要学习下Knockout.js,这个组件很早前听说过,但一直没尝试使用,这两天学习了下,觉得它真心不错,双向绑定的机制简直太爽了.今天打算结合bootstrapTable和Kno ...

  7. JS组件系列——BootstrapTable 行内编辑解决方案:x-editable

    前言:之前介绍bootstrapTable组件的时候有提到它的行内编辑功能,只不过为了展示功能,将此一笔带过了,罪过罪过!最近项目里面还是打算将行内编辑用起来,于是再次研究了下x-editable组件 ...

  8. JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(四):自定义T4模板快速生成页面

    前言:上篇介绍了下ko增删改查的封装,确实节省了大量的js代码.博主是一个喜欢偷懒的人,总觉得这些基础的增删改查效果能不能通过一个什么工具直接生成页面效果,啥代码都不用写了,那该多爽.于是研究了下T4 ...

  9. JS组件系列——Bootstrap组件福利篇:几款好用的组件推荐(二)

    前言:上篇 JS组件系列——Bootstrap组件福利篇:几款好用的组件推荐 分享了几个项目中比较常用的组件,引起了许多园友的关注.这篇还是继续,因为博主觉得还有几个非常简单.实用的组件,实在不愿自己 ...

随机推荐

  1. 【实战分享】又拍云 OpenResty / Nginx 服务优化实践

    2018 年 11 月 17 日,由 OpenResty 主办的 OpenResty Con 2018 在杭州举行.本次 OpenResty Con 的主题涉及 OpenResty 的新开源特性.业界 ...

  2. IView组件化之部署及按钮学习

    IView是什么? iView 是一套基于 Vue.js 的开源 UI 组件库,主要服务于 PC 界面的中后台产品. Npm安装IView npm install iview 在main.js中配置I ...

  3. Spring Cloud中的负载均衡策略

    在上篇博客(Spring Cloud中负载均衡器概览)中,我们大致的了解了一下Spring Cloud中有哪些负载均衡器,但是对于负载均衡策略我们并没有去详细了解,我们只是知道在BaseLoadBal ...

  4. Chapter 4 Invitations——17

    "Then why —"He shrugged. "I was hoping you were just letting him down easy." “这为 ...

  5. Asp.Net SignalR Hub类中的操作详解

    Hub类中的操作 在服务端我们要通过Hub类做一系列操作,下面就说说我们都可以做什么操作 客户端的发送消息操作 调用所有的客户端的helloClient方法 Clients.All.helloClie ...

  6. 精读《syntax-parser 源码》

    1. 引言 syntax-parser 是一个 JS 版语法解析器生成器,具有分词.语法树解析的能力. 通过两个例子介绍它的功能. 第一个例子是创建一个词法解析器 myLexer: import { ...

  7. docker 常用命令和使用

    首先安装Docker CE 在ubantu上,参照https://docs.docker.com/install/linux/docker-ce/ubuntu/#set-up-the-reposito ...

  8. Docker系列04—Docker的网络模式详解

    本文收录在容器技术学习系列文章总目录 1.Docker的四种网络模式 (1)docker四种网络模式如下: Bridge contauner   桥接式网络模式 Host(open) containe ...

  9. Python迭代和解析(5):搞懂生成器和yield机制

    解析.迭代和生成系列文章:https://www.cnblogs.com/f-ck-need-u/p/9832640.html 何为生成器 生成器的wiki页:https://en.wikipedia ...

  10. haproxy使用演示--技术流ken

    haproxy简介 HAProxy提供高可用性.负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费.快速并且可靠的一种解决方案.基于合理的配置及优化,完全可以实现单机支持数 以万计的并 ...