CMDB-表格组件
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <link rel="stylesheet" href="/static/plugins/bootstrap/css/bootstrap.min.css"> 7 </head> 8 <body> 9 <div style="margin: 0 auto;width: 900px;position:relative;"> 10 <h1>资产列表</h1> 11 <div class="row" style="position:absolute;left: 0;"> 12 <form class="navbar-form navbar-left" role="search" style="padding: 0;"> 13 <div class="bs-example " style="float: left;" > 14 <button id="idCheckAll" type="button" class="btn btn-default">全选</button> 15 <button id="idReversAll" type="button" class="btn btn-default">反选</button> 16 <button id="idCancelAll" type="button" class="btn btn-default">取消</button> 17 <button id="idEdit" type="button" class="btn btn-default">批量编辑</button> 18 <button id="idDelete" type="button" class="btn btn-default">批量删除</button> 19 <button id="idSave" type="button" class="btn btn-default">保存</button> 20 </div> 21 22 <div style="float: right;position:absolute;right: 0"> 23 <input type="text" class="form-control" placeholder="Search"> 24 <button type="submit" class="btn btn-default">搜索</button> 25 </div> 26 </form> 27 <table class="table table-bordered"> 28 <thead id="table_th"></thead> 29 <tbody id="table_td"></tbody> 30 </table> 31 <nav aria-label="Page navigation"> 32 <ul id="idPagination" class="pagination"> 33 34 </ul> 35 </nav> 36 </div> 37 </div> 38 <script src="/static/js/jquery-3.1.1.js"></script> 39 <script src="/static/js/NBlist.js"></script> 40 <script> 41 $(function () { 42 $.NB("{% url 'datajson' %}"); 43 $.ChangePager(); 44 }) 45 </script> 46 </body> 47 48 </html>
1 /** 2 * Created by Administrator on 2018-12-02. 3 */ 4 (function () { 5 /*进入编辑模式*/ 6 function IntoEdit($currentr) { 7 $currentr.addClass('success'); 8 $currentr.attr('isedit','true'); 9 //循环tr得每个td属性 10 $currentr.children().each(function () { 11 var EditEnable = $(this).attr('edit-enable'); 12 var EditType = $(this).attr('edit-type'); 13 //可以编辑 14 if(EditEnable == 'true'){ 15 if(EditType == 'select'){ 16 //下拉框 17 var globalName = $(this).attr('global-name'); 18 var old_val = $(this).attr('old_val'); //数据库id 19 //生成select标签 20 var sel = document.createElement('select'); 21 $.each(window[globalName],function (k1,v1) { 22 var op = document.createElement('option'); 23 op.setAttribute('value',v1[0]); 24 op.innerHTML = v1[1]; 25 $(sel).append(op); 26 }); 27 sel.className = "form-control"; 28 //select 默认值 29 $(sel).val(old_val); 30 $(this).html(sel); 31 32 //文本框 33 }else if(EditType == 'input'){ 34 // 获取文本值 35 var innerText = $(this).text(); 36 //创建input 37 var tag = document.createElement('input'); 38 //为input赋值 39 tag.className = "form-control"; 40 tag.value = innerText; 41 $(this).html(tag); 42 } 43 } 44 }) 45 } 46 /*退出编辑模式*/ 47 function OutEdit($currentr) { 48 $currentr.removeClass('success'); 49 $currentr.children().each(function () { 50 var EditEnable = $(this).attr('edit-enable'); 51 var editType = $(this).attr('edit-type'); 52 if(EditEnable == 'true'){ 53 if (editType == 'select'){ 54 //获取正在编辑的selected对象 55 var $select = $(this).children().first(); 56 //获取选中的option的value 57 var newId = $select.val(); 58 //获取选中的option文本内容 59 var newText = $select[0].selectedOptions[0].innerHTML; 60 //在td中设置文本内容 61 $(this).html(newText); 62 //将新值添加到属性中 63 $(this).attr('new-val',newId); 64 65 }else if(editType == 'input'){ 66 //退出编辑模式 67 var inputvalue = $(this).children().first().val(); 68 //在td中设置文本内容 69 $(this).html(inputvalue); 70 //将新值添加到属性中 71 $(this).attr('new-val',inputvalue); 72 } 73 } 74 }) 75 } 76 /*编辑模式*/ 77 function bindEdit() { 78 $('#idEdit').click(function () { 79 var editing =$('#idEdit').hasClass("btn-warning"); 80 if (editing){ 81 //退出编辑 82 $('#idEdit').removeClass("btn-warning"); 83 $('#idEdit').text('批量编辑'); 84 $('#table_td').find(':checked').each(function () { 85 var $currentr = $(this).parent().parent(); 86 OutEdit($currentr); 87 }) 88 }else { 89 //进入编辑 90 $('#idEdit').addClass("btn-warning"); 91 $('#idEdit').text('退出编辑'); 92 $('#table_td').find(':checked').each(function () { 93 var $currentr = $(this).parent().parent(); 94 IntoEdit($currentr); 95 }) 96 } 97 }) 98 } 99 /*绑定复选框*/ 100 function bindCheckBox() { 101 $('#table_td').on('click',':checkbox',function () { 102 var isEdit = $('#idEdit').hasClass('btn-warning'); 103 if (isEdit){ 104 var ck = $(this).prop('checked'); 105 var $currentr = $(this).parent().parent(); 106 if(ck){ 107 // 进入编辑 108 IntoEdit($currentr); 109 }else { 110 //退出编辑 111 OutEdit($currentr); 112 } 113 }else { 114 115 } 116 }) 117 } 118 /*全选*/ 119 function IsCheckAll() { 120 $('#idCheckAll').click(function () { 121 $('#table_td').find(':checkbox').each(function () { 122 if($('#idEdit').hasClass('btn-warning')){ 123 if($(this).prop('checked')){ 124 //已经进入编辑模式了 125 }else { 126 //进入编辑模式 127 var $currentr = $(this).parent().parent(); 128 IntoEdit($currentr); 129 $(this).prop('checked',true); 130 } 131 }else { 132 $(this).prop('checked',true); 133 } 134 }) 135 }) 136 } 137 /*取消*/ 138 function IsCancelAll() { 139 $('#idCancelAll').click(function () { 140 $('#table_td').find(':checked').each(function () { 141 if($('#idEdit').hasClass('btn-warning')){ 142 $(this).prop('checked',false); 143 //退出编辑模式 144 var $currentr = $(this).parent().parent(); 145 OutEdit($currentr); 146 }else { 147 $(this).prop('checked',false); 148 } 149 }) 150 }) 151 } 152 /*反选*/ 153 function IsReversAll() { 154 $('#idReversAll').click(function () { 155 $('#table_td').find(':checkbox').each(function () { 156 if($('#idEdit').hasClass('btn-warning')){ 157 if($(this).prop('checked')){ 158 $(this).prop('checked',false); 159 var $currentr = $(this).parent().parent(); 160 OutEdit($currentr); 161 }else { 162 $(this).prop('checked',true); 163 var $currentr = $(this).parent().parent(); 164 IntoEdit($currentr); 165 } 166 }else { 167 if($(this).prop('checked')){ 168 $(this).prop('checked',false); 169 }else { 170 $(this).prop('checked',true); 171 } 172 } 173 }) 174 }) 175 } 176 /*保存*/ 177 function bindSave() { 178 $('#idSave').click(function () { 179 var postList = []; 180 //找到编辑过得tr 属性isedit="true" 181 $('#table_td').find('tr[isedit="true"]').each(function () { 182 var temp = {}; 183 var row_id = $(this).attr('row-id'); //数据库对应id 184 temp['id'] = row_id; 185 $(this).children('[edit-enable="true"]').each(function () { 186 var name = $(this).attr('name'); 187 var old_val = $(this).attr('old_val'); 188 var new_val = $(this).attr('new-val'); 189 if(old_val != new_val) { 190 temp[name] = new_val; 191 } 192 }); 193 postList.push(temp); 194 }); 195 196 $.ajax({ 197 url:DataJsonUrl, 198 type:'POST', 199 data:{'type':'update','post_list':JSON.stringify(postList),csrfmiddlewaretoken: '{{ csrf_token }}'}, 200 dataType:'JSON', 201 success:function (arg) { 202 if(arg.status){ 203 init(1); 204 console.log(arg.message); 205 }else { 206 console.log(arg.message); 207 } 208 } 209 }) 210 }) 211 } 212 /*删除*/ 213 function bindDel() { 214 // $('#idDelete').click(function () { 215 // $('#table_td').find(':checked').each(function () { 216 // //var row_id = $(this).attr('row-id'); //数据库对应id 217 // var row_id = $(this).parent().parent().attr("row-id"); 218 // 219 // $.ajax({ 220 // url:DataJsonUrl, 221 // type:'POST', 222 // data:{'type':'delete','post_list':row_id,csrfmiddlewaretoken: '{{ csrf_token }}'}, 223 // dataType:'JSON', 224 // success:function (arg) { 225 // if(arg.status){ 226 // init(); 227 // console.log(arg.message); 228 // }else { 229 // console.log(arg.message); 230 // } 231 // } 232 // }) 233 // }) 234 // }) 235 236 } 237 238 239 /*自定义格式化方法*/ 240 String.prototype.format = function (kwargs) { 241 //this "ceshiceshi:{age}-{gender}" 242 //kwargs {'age':18,'gender':'女'} 243 244 var ret = this.replace(/\{(\w+)\}/g,function (km,m) { 245 return kwargs[m] 246 }); 247 return ret 248 }; 249 /*初始化*/ 250 function init(pager) { 251 $.ajax({ 252 url:DataJsonUrl, 253 type:'GET', 254 data:{'pager':pager}, 255 dataType:'JSON', 256 success:function (result) { 257 initGlobalData(result.global_dict); 258 initHeader(result.table_config); 259 initBody(result.table_config,result.data_list); 260 initPager(result.pager); 261 } 262 }) 263 } 264 /*生成表头*/ 265 function initHeader(table_config) { 266 /*创建tr标签*/ 267 var tr = document.createElement('tr'); 268 /*创建tr下th标签并取值*/ 269 $.each(table_config,function (k,item) { 270 if (item.display){ 271 var th = document.createElement('th'); 272 th.innerHTML = item.title; 273 $(tr).append(th); 274 } 275 }); 276 $('#table_th').empty(); 277 $('#table_th').append(tr); 278 } 279 /*生成数据*/ 280 function initBody(table_config,data_list) { 281 $('#table_td').empty(); 282 $.each(data_list,function (k,row) { 283 /*创建tr标签*/ 284 var tr = document.createElement('tr'); 285 tr.setAttribute('row-id',row['id']); 286 /*根据配置文件显示字段*/ 287 $.each(table_config,function (i,colConfig) { 288 if(colConfig.display){ 289 var td = document.createElement('td'); 290 //对colConfig.text.kwargs去@重写 291 //生成文本信息 292 var kwargs = {}; 293 $.each(colConfig.text.kwargs,function (key,value) { 294 if(value.substring(0,2) == '@@'){ 295 var global_name = value.substring(2,value.length); //全局变量名称 296 var global_id = row[colConfig.q]; //获取数据库数字类型的值 297 var temp_id = GetTextFromGlobalById(global_name,global_id); 298 kwargs[key] = temp_id 299 } 300 else if(value[0]=='@'){ 301 kwargs[key] = row[value.substring(1,value.length)]; //数据库里的字段.使用row[] 302 }else { 303 kwargs[key] = value; //配置文件默认值 304 } 305 }); 306 var temp = colConfig.text.content.format(kwargs); 307 td.innerHTML = temp; 308 //设置属性colConfig.attr 309 $.each(colConfig.attr,function (kk,vv) { 310 //处理attr里得origin带@得数值 311 if(vv[0]=='@'){ 312 td.setAttribute(kk,row[vv.substring(1,vv.length)]); 313 }else { 314 td.setAttribute(kk,vv); 315 } 316 }); 317 318 $(tr).append(td) 319 } 320 }); 321 $('#table_td').append(tr); 322 }); 323 } 324 /*设置全局变量*/ 325 function initGlobalData(global_dict) { 326 $.each(global_dict,function (k,v) { 327 window[k] = v; //设置为全局变量 328 }) 329 } 330 /*设置数据库内存数据*/ 331 function GetTextFromGlobalById(global_name,global_id) { 332 var ret =null; 333 $.each(window[global_name],function (k,item) { 334 if(item[0] == global_id){ 335 ret = item[1]; 336 return 337 } 338 }); 339 return ret; 340 } 341 /*页码改变*/ 342 function bindChangePager() { 343 $('#idPagination').on('click','a',function () { 344 var num = $(this).attr('pnum'); 345 init(num); 346 }) 347 } 348 /*分页*/ 349 function initPager(pager) { 350 $('#idPagination').html(pager); 351 } 352 353 /*初始加载数据*/ 354 jQuery.extend({ 355 'NB': function (url) { 356 DataJsonUrl = url; 357 init(); 358 bindEdit(); 359 bindCheckBox(); 360 IsCheckAll(); 361 IsCancelAll(); 362 IsReversAll(); 363 bindSave(); 364 bindDel(); 365 bindChangePager(); 366 }, 367 'ChangePager':function (num) { 368 init(num); 369 } 370 }) 371 })();
后端代码:
1 from django.urls import path 2 from webdemo import views 3 urlpatterns = [ 4 path('', views.index), 5 path('datajson/', views.datajson,name='datajson'), 6 7 ]
1 from django.shortcuts import render,HttpResponse 2 from DB import models 3 import json 4 from unitpub.pager_Class import Pagination 5 # Create your views here. 6 7 8 def index(req): 9 """ 10 数据库获取数据 11 :param req: 12 :return: 13 """ 14 return render(req,'tabledemo.html') 15 16 17 def datajson(req): 18 """ 19 从数据库获取数据 20 :param req: 21 :return: 22 """ 23 if req.method == 'POST': 24 ret = {'status': False, 'message': '数据没有任何变化'} 25 data_list = req.POST.get('post_list') 26 data_type = req.POST.get('type') 27 if data_type == 'update': 28 for data in json.loads(data_list): 29 if len(data) > 1: 30 # print(data) 31 isupdate = models.Asset.objects.filter(id=data['id']).update(**data) 32 if isupdate: 33 ret['status'] = True 34 ret['message'] = '更新成功' 35 return HttpResponse(json.dumps(ret)) 36 elif data_type == 'delete': 37 isdelete = models.Asset.objects.filter(id=data_list).delete() 38 if isdelete: 39 ret['status'] = True 40 ret['message'] = '删除数据' 41 return HttpResponse(json.dumps(ret)) 42 else: 43 return HttpResponse(json.dumps(ret)) 44 else: 45 # q:数据库字段 46 # title:显示表头 47 # display:是否显示 48 # text:{'content':"{m}-{n}",'kwargs':{'m':'某机房','n':'@cabinet_order'}} 字符串格式化带@符号取数据库否则固定值 49 # @@代表取数据库内存值 50 """ 51 'attr':{ 52 'name': 'idc_id', 更新时更新数据库什么字段 53 'old_val': '@idc__id', 为了让编辑时select得value值与数据库id一致 54 'edit-enable': 'true', 是否编辑 55 'edit-type': 'select', 前端类型 56 'global-name':'idc_choices' 全局变量名字 57 } 58 """ 59 table_config=[ 60 # 配置选项 61 { 62 'q': None, 63 'title': "选项", 64 'display': True, 65 'text': {'content': "<input type='checkbox'/>", 'kwargs': {}}, 66 'attrs': {}, 67 }, 68 # 配置id 69 { 70 'q': 'id', 71 'title':'ID', 72 'display':False, 73 'text':{}, 74 'attr':{} 75 }, 76 # 配置类型 77 { 78 'q': 'device_type_id', 79 'title': '资产类型', 80 'display': True, 81 'text': {'content':"{n}",'kwargs':{'n':'@@device_type_choices'}}, 82 'attr':{ 83 'name':'device_type_id', 84 'old_val': '@device_type_id', 85 'edit-enable': 'true', 86 'edit-type': 'select', 87 'global-name': 'device_type_choices' 88 } 89 }, 90 # 配置类型 91 { 92 'q': 'device_status_id', 93 'title': '状态', 94 'display': True, 95 'text': {'content': "{n}", 'kwargs': {'n': '@@device_status_choices'}}, 96 'attr':{ 97 'name':'device_status_id', 98 'old_val': '@device_status_id', 99 'edit-enable': 'true', 100 'edit-type': 'select', 101 'global-name': 'device_status_choices' 102 } 103 }, 104 # 配置数据:ForeignKey 为了select框单独取id才能有默认值 105 { 106 'q': 'idc__id', 107 'title': 'IDC', 108 'display': False, 109 'text': {}, 110 'attr': {} 111 }, 112 # 配置数据:ForeignKey 113 { 114 'q': 'idc__name', 115 'title': 'IDC', 116 'display': True, 117 'text': {'content': "{n}", 'kwargs': {'n': '@idc__name'}}, 118 'attr':{ 119 'name': 'idc_id', # 注意是单下划线 120 'old_val': '@idc__id', 121 'edit-enable': 'true', 122 'edit-type': 'select', 123 'global-name':'idc_choices' 124 } 125 }, 126 # 配置数据 127 { 128 'q': 'cabinet_num', 129 'title': '机柜号', 130 'display': True, 131 'text': {'content':"{n}",'kwargs':{'n':'@cabinet_num'}}, 132 'attr':{ 133 'name': 'cabinet_num', 134 'old_val': '@cabinet_num', 135 'edit-enable': 'true', 136 'edit-type': 'input' 137 } 138 }, 139 # 配置数据 140 { 141 'q': 'cabinet_order', 142 'title': '机柜位置', 143 'display': True, 144 'text': {'content':"{m}-{n}",'kwargs':{'m':'某机房','n':'@cabinet_order'}}, 145 'attr':{ 146 'name': 'cabinet_order', 147 'old_val': '@cabinet_order', 148 'edit_enable':'true', 149 'edit_type':'input', 150 } 151 }, 152 # 配置操作 153 { 154 'q': None, 155 'title': '操作', 156 'display': True, 157 'text': {'content': "<a href='/data_show-{x}/'>{n}</a> <a href='/data_show-{x}/'>{m}</a>", 'kwargs': {'n': '详情','m': '编辑', 'x':'@id'}}, 158 'attr': {} 159 } 160 ] 161 162 q_list = [] 163 for i in table_config: 164 if not i['q']: 165 continue 166 q_list.append(i['q']) 167 168 # 数据库取哪几列数据 169 data_list = models.Asset.objects.all().values(*q_list) 170 data_list = list(data_list) 171 172 # 分页 173 data_count = models.Asset.objects.count() 174 current_page = req.GET.get('pager') 175 page_obj = Pagination(data_count, current_page) 176 data_list = data_list[page_obj.start():page_obj.end()] 177 178 result = { 179 'table_config':table_config, # 配置文件 180 'data_list':data_list, # 构造数据 181 'global_dict':{ 182 'device_type_choices': models.Asset.device_type_choices, # 内存中的类型 183 'device_status_choices': models.Asset.device_status_choices, # 内存中的类型 184 'idc_choices': list(models.IDC.objects.values_list('id', 'name')), 185 }, 186 'pager': page_obj.page_str(), 187 } 188 189 return HttpResponse(json.dumps(result))
1 ''' 2 TotalNumber:总个数 3 CurrentPage:当前页【1/2/3/4/5/6/7】 4 barsNumber:每页显示多少条【10条数据】 5 MaxPageNumber:最大显示多少个【1,2,3,4,5,6,7】 6 ''' 7 8 class Pagination(object): 9 def __init__(self,TotalNumber,CurrentPage,barsNumber=5,MaxPageNumber=7): 10 self.Total_number=TotalNumber 11 try: 12 v = int(CurrentPage) 13 if v<=0: 14 v=1 15 self.Current_page=v 16 except Exception as e: 17 self.Current_page = 1 18 self.bars_number=barsNumber 19 self.Max_pageNumber=MaxPageNumber 20 # 起始数据 21 def start(self): 22 return (self.Current_page - 1) * self.bars_number 23 # 结束数据 24 def end(self): 25 return self.Current_page * self.bars_number 26 27 # 总页数 28 @property 29 def num_pages(self): 30 ''' 31 总页数 32 :return: 33 ''' 34 a,b = divmod(self.Total_number,self.bars_number) 35 if b==0: 36 return a 37 else: 38 return a+1 39 40 # 显示页码数 41 def page_num_range(self): 42 #总页数小于显示页码 43 if self.num_pages < self.Max_pageNumber: 44 return range(1,self.num_pages+1) 45 #总页数很多 46 part = int(self.Max_pageNumber/2) 47 if self.Current_page <= part: 48 return range(1,self.Max_pageNumber+1) 49 if (self.Current_page+part) > self.num_pages: 50 return range(self.num_pages-self.Max_pageNumber,self.num_pages+1) 51 return range(self.Current_page-part,self.Current_page+part+1) 52 53 # 返回页码给前端 54 def page_str(self): 55 page_list=[] 56 # 首页 57 first="<li><a pnum='1'>首页</a></li>" 58 page_list.append(first) 59 # 上一页 60 if self.Current_page ==1 : 61 prev="<li><a href='javascript:void(0)'>上一页</a></li>" 62 else: 63 prev="<li><a pnum='%d'>上一页</a></li>" % (self.Current_page-1) 64 page_list.append(prev) 65 # 页码 66 for i in self.page_num_range(): 67 if i == self.Current_page: 68 temp = "<li pnum='%d' class='active'><a>%s</a></li>" % (i,i) 69 else: 70 temp="<li><a pnum='%d'>%s</a></li>" % (i,i) 71 page_list.append(temp) 72 # 下一页 73 if self.Current_page == self.num_pages : 74 next_page="<li><a href='javascript:void(0)'>下一页</a></li>" 75 else: 76 next_page="<li><a pnum='%d'>下一页</a></li>" % (self.Current_page+1) 77 page_list.append(next_page) 78 # # 尾页 79 end_page = "<li><a pnum='%d'>尾页</a></li>" % self.num_pages 80 page_list.append(end_page) 81 # 页码概要 82 end_html = "<li><a href='javascript:void(0)' >共 %d页 / %d 条数据</a></li>" % (self.num_pages, self.Total_number,) 83 page_list.append(end_html) 84 return ''.join(page_list)
数据库:
1 class Asset(models.Model): 2 """ 3 资产信息表,所有资产公共信息(交换机,服务器,防火墙等) 4 """ 5 device_type_choices = ( 6 (1, '服务器'), 7 (2, '交换机'), 8 (3, '防火墙'), 9 ) 10 device_status_choices = ( 11 (1, '上架'), 12 (2, '在线'), 13 (3, '离线'), 14 (4, '下架'), 15 ) 16 17 device_type_id = models.IntegerField(choices=device_type_choices, default=1) 18 device_status_id = models.IntegerField(choices=device_status_choices, default=1) 19 20 cabinet_num = models.CharField('机柜号', max_length=30, null=True, blank=True) 21 cabinet_order = models.CharField('机柜中序号', max_length=30, null=True, blank=True) 22 23 idc = models.ForeignKey('IDC', verbose_name='IDC机房', null=True, blank=True,on_delete=models.CASCADE) 24 business_unit = models.ForeignKey('BusinessUnit', verbose_name='属于的业务线', null=True, blank=True,on_delete=models.CASCADE) 25 26 tag = models.ManyToManyField('Tag') 27 28 latest_date = models.DateField(null=True) 29 create_at = models.DateTimeField(auto_now_add=True) 30 31 class Meta: 32 verbose_name_plural = "资产表" 33 34 def __str__(self): 35 return "%s-%s-%s" % (self.idc.name, self.cabinet_num, self.cabinet_order)

浙公网安备 33010602011771号