2 Commits
v2.17 ... v2.19

Author SHA1 Message Date
RobbieHan
e3490b3af7 tags&filters 2019-02-17 22:40:06 +08:00
RobbieHan
b58be33aac change_compare 2019-02-12 21:21:00 +08:00
11 changed files with 328 additions and 6 deletions

View File

@@ -20,7 +20,7 @@ class AbstractMode(models.Model):
class Code(AbstractMode):
key = models.CharField(max_length=80, verbose_name='')
value = models.CharField(max_length=80, verbose_name='')
desc = models.BooleanField(default=True, verbose_name='备注')
desc = models.CharField(max_length=100, blank=True, default='', verbose_name='备注')
class Meta:
verbose_name = '字典'

View File

@@ -1,13 +1,39 @@
import os
from django.dispatch import receiver
from django.db.models.signals import post_delete
from django.db.models.signals import post_delete, post_save
from .models import DeviceFile
from .models import DeviceFile, DeviceInfo
from utils.db_utils import MongodbDriver
@receiver(post_delete, sender=DeviceFile)
def auto_delete_file(sender, instance, **kwargs):
if instance.file_content:
if os.path.isfile(instance.file_content.path):
os.remove(instance.file_content.path)
os.remove(instance.file_content.path)
@receiver(post_save, sender=DeviceInfo)
def auto_compare_diff(sender, instance, **kwargs):
record = instance.history.latest()
prev_record = record.prev_record
ope_type = {'~': 'update', '+': 'create', '-': 'delete'}
compare_result = {
'id': record.id,
'changed_by': record.changed_by.name,
'history_type': ope_type[record.history_type],
'history_date': record.history_date
}
changes = {}
if prev_record is not None:
delta = record.diff_against(prev_record)
for change in delta.changes:
changes[change.field] = [change.old, change.new]
compare_result['changes'] = changes
if compare_result['changes'] or compare_result['history_type'] == 'create':
try:
mongo = MongodbDriver(collection='change_compare')
mongo.insert(compare_result)
except Exception as e:
pass

View File

@@ -0,0 +1,3 @@
# @Time : 2019/2/17 21:28
# @Author : RobbieHan
# @File : __init__.py.py

View File

@@ -0,0 +1,60 @@
from django import template
from django.db.models.query import QuerySet
from django.contrib.auth import get_user_model
from cmdb.models import Code, Cabinet
register = template.Library()
User = get_user_model()
@register.simple_tag
def get_con(context, arg, field):
if isinstance(context, QuerySet):
context = context.values()
instance = [con for con in context if con['id'] == arg]
if instance:
return instance[0][field]
return ''
@register.filter(name='compare_result')
def get_change_compare(changes):
change_compare = []
for key, value in changes.items():
if key in ['network_type', 'service_type', 'operation_type']:
log = replace_log(key, value, Code, 'value')
elif key == 'dev_cabinet':
log = replace_log(key, value, Cabinet, 'number')
elif key == 'leader':
log = replace_log(key, value, User, 'name')
else:
log = '字段:"%(field)s",由:"%(old)s",变更为:"%(new)s"' % {
'field': key,
'old': value[0],
'new': value[1]
}
change_compare.append(log)
return ''.join(str(i) for i in change_compare)
def replace_log(key, value, model, field):
old = value[0]
new = value[1]
log_format = '字段:"%(field)s",由:"%(old)s",变更为:"%(new)s"'
try:
data = model.objects.filter(id=old).values()[0]
old_data = data[field]
except Exception:
old_data = old
try:
data = model.objects.filter(id=new).values()[0]
new_data = data[field]
except Exception:
new_data = new
return log_format % {
'field': key,
'old': old_data,
'new': new_data
}

View File

@@ -33,4 +33,5 @@ urlpatterns = [
path('eam/device/list/', views_eam.DeviceListView.as_view(), name='eam-device-list'),
path('eam/device/delete/', views_eam.DeviceDeleteView.as_view(), name='eam-device-delete'),
path('eam/device/device2connection/', views_eam.Device2ConnectionView.as_view(), name='eam-device-device2connection'),
path('eam/device/detail/', views_eam.DeviceDetailView.as_view(), name='eam-device-detail'),
]

View File

@@ -11,6 +11,7 @@ from custom import (BreadcrumbMixin, SandboxDeleteView,
SandboxListView, SandboxUpdateView, SandboxCreateView)
from .models import Cabinet, DeviceInfo, Code, ConnectionInfo
from .forms import DeviceCreateForm, DeviceUpdateForm, ConnectionInfoForm
from utils.db_utils import MongodbDriver
User = get_user_model()
@@ -157,4 +158,20 @@ class Device2ConnectionView(LoginRequiredMixin, View):
form_errors = str(form.errors)
errors = re.findall(pattern, form_errors)
res['error'] = errors[0]
return JsonResponse(res)
return JsonResponse(res)
class DeviceDetailView(LoginRequiredMixin, BreadcrumbMixin, TemplateView):
template_name = 'cmdb/deviceinfo_detail.html'
def get_context_data(self, **kwargs):
device = get_object_or_404(DeviceInfo, pk=int(self.request.GET['id']))
mongo = MongodbDriver()
logs = mongo.find(id=int(self.request.GET['id']), sort_by='history_date')
all_file = device.devicefile_set.all()
device_public = get_device_public()
kwargs['device'] = device
kwargs['logs'] = logs
kwargs['all_file'] = all_file
kwargs.update(device_public)
return super().get_context_data(**kwargs)

18
apps/utils/db_utils.py Normal file
View File

@@ -0,0 +1,18 @@
import pymongo
class MongodbDriver(object):
def __init__(self, db='device', collection='change_compare'):
self.client = pymongo.MongoClient('127.0.0.1', 27017)
self.db = self.client[db]
self.col = self.db[collection]
def insert(self, content):
return self.col.insert(content)
def find(self, sort_by, **filters,):
data = self.col.find(filters)
if sort_by:
data.sort(sort_by, pymongo.DESCENDING)
return data

View File

@@ -44,6 +44,7 @@ INSTALLED_APPS = [
'simple_history',
'system',
'cmdb',
'cmdb.templatetags',
]
MIDDLEWARE = [

View File

@@ -40,7 +40,7 @@
</div>
<label class="col-sm-2 control-label">描述信息</label>
<div class="col-sm-3">
<input class="form-control" id="desc" name="desc" type="text" />
<input class="form-control" id="desc" name="desc" type="text" value="{{ code.desc }}"/>
</div>
</div>

View File

@@ -339,5 +339,9 @@
}
});
}
function doDetail(id){
window.location.href="{% url 'cmdb:eam-device-detail' %}?id="+id;
}
</script>
{% endblock %}

View File

@@ -0,0 +1,192 @@
{% extends "base-left.html" %}
{% load staticfiles %}
{% load extra_tags %}
{% block css %}
<link rel="stylesheet" href="{% static 'js/plugins/layer/skin/layer.css' %}">
{% endblock %}
{% block content %}
<section class="content">
<div class="nav-tabs-custom">
<ul class="nav nav-tabs">
<li class="active"><a href="#activity" data-toggle="tab">设备详情</a></li>
<li><a href="#history" data-toggle="tab">历史纪录</a></li>
</ul>
<div class="tab-content">
<div class="active tab-pane" id="activity">
<div class="box-body no-padding">
<div class="btn-group pull-right margin">
<button type="button" class="btn btn-primary btn-sm margin-r-5"
onclick="doUpload({{ device.id }})">
<i class="fa fa-cloud-upload"> 上传资料</i>
</button>
<button type="button" class="btn btn-primary btn-sm margin-r-5" title="认证管理" onclick="doDevice2Connection({{ device.id }})">
<i class="fa fa-user"> 认证管理</i>
</button>
<button type="button" class="btn btn-primary btn-sm margin-r-5" title="自动更新" onclick="doAutoUpdate({{ device.id }})">
<i class="fa fa-circle-o-notch"> 自动更新</i>
</button>
<button type="button" class="btn btn-primary btn-sm margin-r-5" title="编辑" onclick="doUpdate({{ device.id }})">
<i class="fa fa-pencil"> 编辑</i>
</button>
<button type="button" id="btnReturn" class="btn btn-primary btn-sm">
<i class="fa fa-arrow-left"></i> 返回
</button>
</div>
</div>
<div class="table-responsive mailbox-messages">
<table class="table" id="tbWorkList" style="white-space: nowrap;">
<tbody>
<tr class="info">
<td width="10%"><strong>主机名</strong></td>
<td class="text-left">{{ device.sys_hostname }}</td>
<td width="10%"><strong>SN编号</strong></td>
<td class="text-left">{{ device.sn_number }}</td>
</tr>
<tr>
<td><strong>系统类型</strong></td>
<td>{{ device.os_type }}</td>
<td><strong>设备类型</strong></td>
<td>{{ device.device_type }}</td>
</tr>
<tr class="info">
<td><strong>设备地址</strong></td>
<td>{{ device.hostname }}</td>
<td><strong>MAC地址</strong></td>
<td>{{ device.mac_address }}</td>
</tr>
<tr>
<td><strong>网络类型</strong></td>
<td>{% get_con all_code device.network_type 'value' %}</td>
<td><strong>服务类型</strong></td>
<td>{% get_con all_code device.service_type 'value' %}</td>
</tr>
<tr class="info">
<td><strong>业务类型</strong></td>
<td>{% get_con all_code device.operation_type 'value' %}</td>
<td><strong>机柜信息</strong></td>
<td>{% get_con all_cabinet device.dev_cabinet 'number' %}</td>
</tr>
<tr>
<td><strong>购买日期</strong></td>
<td>{{ device.buyDate }}</td>
<td><strong>质保日期</strong></td>
<td>{{ device.warrantyDate }}</td>
</tr>
<tr class="info">
<td><strong>所属</strong></td>
<td>{% if device.parent %}
{{ device.parent.sys_hostname }}({{ device.parent.hostname }})
{% endif %}
</td>
<td><strong>责任人</strong></td>
<td>{% get_con all_user device.leader 'name' %}</td>
</tr>
<tr>
<td><strong>入库时间</strong></td>
<td>{{ device.add_time }}</td>
<td><strong>最后变更</strong></td>
<td>{{ device.modify_time }}</td>
</tr>
<tr class="info">
<td><strong>最后操作人</strong></td>
<td>{{ device.changed_by.name }}</td>
<td><strong></strong></td>
<td></td>
</tr>
<tr>
<td><strong>备注信息</strong></td>
<td colspan="3">{{ device.desc }}</td>
</tr>
</tbody>
</table>
</div>
<br>
<div class="box-footer">
<ul class="mailbox-attachments clearfix" id="imageContainer">
{% for file in all_file %}
<li class="imageItem">
<div class="mailbox-attachment-info">
<a href="/media/{{ file.file_content }}" target="_blank"><i
class="fa fa-file-text"></i>
<small>{{ file.file_content|cut:'asset_file/' }}</small>
</a>
<span class="mailbox-attachment-size">
<b>上传人</b>{{ file.upload_user }}
<a href="/media/{{ file.file_content }}" download="{{ file.file_content }}"
class="btn btn-primary btn-xs pull-right">
<i class="fa fa-cloud-download" title="下载文件"></i>
</a>
<button class="btn btn-adn btn-xs pull-right margin-r-5"
onclick="doDelete({{ file.id }})">
<i class="fa fa-trash" title="删除文件"> </i>
</button>
</span>
</div>
</li>
{% endfor %}
</ul>
</div>
</div>
<!-- /.tab-pane -->
<div class="tab-pane" id="history">
<div class="box-body">
<ul class="todo-list">
{% for log in logs %}
<li>
<!-- drag handle -->
<span class="handle">
<small class="text-maroon">
<i class="glyphicon glyphicon-time"></i>
{{ log.history_date }}
&nbsp;&nbsp;
{{ log.changed_by }}
&nbsp;&nbsp;
{{ log.history_type }}
</small>
</span>
<span class="text-sm">
{{ log.changes | compare_result }}
</span>
<!--
<button class="btn btn-xs btn-danger pull-right">还原数据</button>
-->
</li>
{% endfor %}
</ul>
</div>
</div>
<!-- /.tab-pane -->
</div>
<!-- /.tab-content -->
</div>
</section>
<!-- /.content -->
{% endblock %}
{% block javascripts %}
<script src="{% static 'js/plugins/layer/layer.js' %}"></script>
<script src="{% static 'plugins/masonry/masonry.js' %}"></script>
<script type="text/javascript">
$(function () {
$('#CMDB-EAM').addClass('active');
$('#CMDB-EAM-DEVICE').addClass('active');
});
$("#btnReturn").click(function(){
history.back();
});
</script>
{% endblock %}