✨作者主页:IT毕设梦工厂✨
个人简介:曾从事计算机专业培训教学,擅长Java、Python、微信小程序、Golang、安卓Android等。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。
☑文末获取源码☑
精彩专栏推荐⬇⬇⬇
Java项目
Python项目
安卓项目
微信小程序项目
一、开发环境
- 开发语言:Python
- 数据库:MySQL
- 系统架构:B/S
- 后端:Django
- 前端:Vue
二、系统功能模块
- 角色:用户、管理员
- 功能:
用户:
交流论坛、通知公告、投诉建议、在线客服、查询信息管理、认证申请管理、代缴服务管理;
管理员:
用户管理、证件查询管理、查询信息管理、教育培训管理、认证申请管理、便民服务管理、代缴服务管理、投诉建议、交流论坛、通知公告管理、在线客服。
三、系统界面展示
四、部分代码设计
# 用户登录的view
class LoginView(ViewSet):
# 登录不需要认证
authentication_classes = []
# datail=True的时候,查询字符串携带pk
@action(methods=['POST', ], detail=False)
def login(self, request, *args, **kwargs):
username = request.data.get('username')
password = request.data.get('password')
try:
# 用户存在,则一定能拿到用户对象
user = models.User.objects.get(username=username)
ret = user.check_password(password)
except Exception as e:
return ApiResponse(msg='登录失败', code=104, data={'errors': str(e)})
# ret = auth.authenticate(request,**request.data)
if ret:
role=user.role
token = _get_token(user)
user_ser = serializers.CurrentUserSerializer(instance=user)
if role==1 :
father = models.EmunFather.objects.filter(Q(role=role)|Q(admin=role)).order_by('create')
elif role==2:#老板看到的界面,随意拼接其他人的界面
father = models.EmunFather.objects.filter(boss=role).order_by('create')
#部分系统管理的功能老板需要看到,加一些老板独有的功能
elif role==3:#登录的用户的role=3
father=models.EmunFather.objects.filter(Q(manager=role)|Q(part__manager_id=user.id)).order_by('create')
else:
father = models.EmunFather.objects.filter(role=user.role).order_by('create')
rightList = []
for fa in father:
fa_ser = serializers.EmnuFatherSerializer(instance=fa)
children = models.EmnuChildren.objects.filter(father=fa)
children_ser = serializers.EmnuChildrenSerializer(instance=children, many=True)
dic = dict(fa_ser.data)
dic.setdefault('children', children_ser.data)
rightList.append(dic)
return ApiResponse(msg='登录成功', code=100, role=user.role, id=user.id,
token=token,
data=user_ser.data,
right=rightList,
part=user.part_f.name
)
else:
logging.warning('用户登录失败了')
logging.error(str(request.user) + '用户登录失败')
return ApiResponse(msg='用户名或密码错误', code=101)
# 创建单个用户的功能
class CreateUserView(GenericAPIView, CreateModelMixin):
# 权限限制
permission_classes = [permiss.SuperAdminPermission]
queryset = models.User.objects.all()
serializer_class = serializers.CreateUserSerializer
# 重写post请求,创建
def post(self, request):
ser = serializers.CreateUserSerializer(data=request.data)
if ser.is_valid():
return ApiResponse(code=100, data={'username': request.data.get('username')})
else:
return ApiResponse(code=500, msg='创建用户失败', error=ser.errors)
# 自己封装的栈
class Stack():
def __init__(self, lis):
self.lis = lis
# 入栈
def push(self, data):
self.lis.append(data)
# 出栈:使用列表分割的方法,拿栈顶到指定位置的数据
def get_number(self, number):
result = self.lis[-1:-(number + 1):-1]
return result
def get_old_number(self, number):
result = self.lis[:number]
return result
# 封装一个固定长度的队列
class Queue():
def __init__(self, len):
self.leng = len
self.lis = []
def push(self, data):
lis_len = len(self.lis)
if lis_len < self.leng:
self.lis.append(data)
else:
self.lis.append(data)
# 去掉第一个数据。
self.lis = self.lis[1:]
# 拿到队列的数据
def get(self):
return self.lis
# 反转
def get_reverse(self):
return self.lis[::-1]
# 使用生成器拿读取log文件中的内容
def log_data(filename):
from logs.logs_path import LOG_DIR
'''
:param filename: 要读取的日志文件名
:param read_type: 读取文件的方向:true是从最后往开头读
false 是从开头往读
fp.seek(offset,whence):offset是偏移,负值从指针位置往文件前面读,正值从指针位置往后读
whence: 0指针在文件开头、1是指针在当前位置、2是指针在文件最后
:return:
'''
fp = open(os.path.join(LOG_DIR, filename), 'rb')
# size=os.path.getsize(os.path.join(LOG_DIR, filename))
# if read_type:
# #从文件最后往文件开头的方向读内容,
# fp.seek(-int(size),2)
# else:
# #从文件开头读取内容
# fp.seek(int(size),0)
for line in fp.readlines():
try:
line = str(line.decode())
# 使用生成器,这样可以节省内存空间。
except:
continue
yield line
fp.close()
# 使用next来拿到log文件中的内容,其中的get中的max应该是前端传递过来的,
class LogDataView(GenericAPIView, ViewSetMixin):
# 日志信息
def get(self, request):
dat = []
flag = True
# 前端传递过来要读取的日志条数
number = int(request.query_params.get('number'))
if number > 100 or number < 1:
return ApiResponse(code=500, msg='失败', error='搜索范围在1-100之间!!')
# 获取前端传递过来的读取顺序
order_type = int(request.query_params.get('type'))
data = log_data('warning.log')
log_len = 10
# 自己封装的一个栈
stack = Stack([])
queue = Queue(number)
while flag:
try:
line = str(next(data))
if line.startswith('&&'):
y, level, time, module, message = line.split('&&')
if level == 'WARNING':
dic = {'level': level, 'time': time, 'module': module, 'message': message, 'color': '#d25e32'}
else:
dic = {'level': level, 'time': time, 'module': module, 'message': message, 'color': '#930808'}
# stack.push(dic)
queue.push(dic)
if order_type:
# 拿到最新的number条日志
dat = queue.get_reverse()
else:
# 拿到最旧的number条日志
dat = queue.get()
log_len = len(dat)
except StopIteration:
# 如果生成器读到文件最后,继续next就会报错,捕获后就退出循环
flag = False
# 将生成的字典传递给前端进行展示,这个是自己封装的response
return ApiResponse(data=dat, lenth=log_len)
# 日志分析,获取饼状图的数据
def post(self, request):
# table_type=0 #0是饼状图、1是柱状图、2是折线图
flag = True
# 前端传递过来要读取的日志条数
number = int(request.query_params.get('number'))
len_number = number
table_type = int(request.query_params.get('type'))
if number < 10 or number > 300:
return ApiResponse(code=500, msg='失败', error='搜索范围在10-300之间!!')
# 获取前端传递过来的读取顺序
data = log_data('warning.log')
warning = 0
error = 0
critical = 0
data_dic = []
# CRITICAL
# 给队列传入长度,这样队列的长度就不能超过这个长度了
queue = Queue(number)
while flag:
try:
line = str(next(data))
if line.startswith('&&'):
# 拿到要处理的数据
queue.push(line)
except StopIteration:
# 如果生成器读到文件最后,继续next就会报错,捕获后就退出循环
flag = False
# 拿到队列中的数据
line_lis = queue.get()
for line in line_lis:
y, level, time, module, message = line.split('&&')
if level == 'WARNING':
warning += 1
elif level == 'ERROR':
error += 1
else:
critical += 1
all_count = len(line_lis)
if warning > 0:
w = '{:.2f}'.format(warning / all_count * 100) + '%'
data_dic.append({'name': f'WARNING[{warning}]-{w}', 'value': warning})
if error > 0:
w = '{:.2f}'.format(error / all_count * 100) + '%'
data_dic.append({'name': f'ERROR[{error}]-{w}', 'value': error})
if critical > 0:
w = '{:.2f}'.format(critical / all_count * 100) + '%'
data_dic.append({'name': f'CRITICAL[{critical}]-{w}', 'value': critical})
# 最近200条报警按照月份计算
return ApiResponse(data=data_dic, lenth=all_count)
# 日志分析,获取折线图的数据
def put(self, request):
import time
now_year = time.localtime().tm_year # 获取当前的年份
the_year = now_year
now_mount = int(time.localtime().tm_mon)
mon_lis = []
warning_div = {} # {月份:报警数量}
error_div = {} # {月份:报警数量}
# 拿到当前年份的月份列表
for i in range(1, now_mount + 1):
mon_lis.append(i)
warning_div[i] = 0
error_div[i] = 0
# 年份数据是给前端的select使用的
year_lis = [{'label': f'{now_year}年', 'value': int(now_year)}]
year_obj = models.YearLogData.objects.all()
year_ser = serializers.YearLogdataViewSerializer(instance=year_obj, many=True)
for y in year_ser.data:
year_lis.append({'label': f'{y["year"]}年', 'value': int(y["year"])})
# 拿到要查看的年份的日志信息
year = int(request.query_params.get('year'))
# 获取前端传递过来的读取顺序
data = log_data('warning.log')
flag = True
# CRITICAL
warn = {
'data': [],
'type': 'line',
# 'stack': 'x',
'name': "WARNING"
}
error = {
'data': [],
'type': 'line',
# 'stack': 'x',
'name': "ERROR",
}
if year == the_year:
while flag:
try:
line = str(next(data)) # 拿到每行数据
if line.startswith('&&'):
n, level, time, module, message = line.split('&&')
m = time.split('-')[1]
if level == 'WARNING':
warning_div[int(m)] = warning_div[int(m)] + 1
else:
error_div[int(m)] = error_div[int(m)] + 1
except StopIteration:
# 如果生成器读到文件最后,继续next就会报错,捕获后就退出循环
flag = False
for v in warning_div.values():
warn['data'].append(v)
for v in error_div.values():
error['data'].append(v)
datas = [warn, error]
mon_lis = [f'{i}月' for i in mon_lis]
return ApiResponse(data=datas, year=year_lis, mon_lis=mon_lis)
else:
year_obj = models.YearLogData.objects.filter(year=str(year)).first()
if year_obj:
mon_data = models.DetalLogdata.objects.filter(year=year_obj).order_by('order')
ser = serializers.DeatailLogDataViewSerialize(instance=mon_data, many=True)
mount_set = []
for div in ser.data:
if div['type'] == 'WARNING':
warn['data'].append(div['count'])
mount_set.append(div['mount'])
else:
error['data'].append(div['count'])
datas = [warn, error]
return ApiResponse(data=datas, mon_lis=list(mount_set), year=year_lis)
return ApiResponse(code=404, data='没有相应的数据', year=year_lis)
# 日志分析,获取柱状图的数据
def patch(self, request):
import time
now_year = time.localtime().tm_year # 获取当前的年份
the_year = now_year
now_mount = int(time.localtime().tm_mon)
mon_lis = []
warning_div = {} # {月份:报警数量}
error_div = {} # {月份:报警数量}
# 拿到当前年份的月份列表
for i in range(1, now_mount + 1):
mon_lis.append(i)
warning_div[i] = 0
error_div[i] = 0
# 年份数据是给前端的select使用的
year_lis = [{'label': f'{now_year}年', 'value': now_year}]
# for i in range(4):
# now_year -= 1
# year_lis.append({'label': f'{now_year}年', 'value': now_year})
year_obj = models.YearLogData.objects.all()
year_ser = serializers.YearLogdataViewSerializer(instance=year_obj, many=True)
for y in year_ser.data:
year_lis.append({'label': f'{y["year"]}年', 'value': int(y["year"])})
# 拿到要查看的年份的日志信息
year = int(request.query_params.get('year'))
# 获取前端传递过来的读取顺序
data = log_data('warning.log')
flag = True
# CRITICAL
warn = {
'data': [],
'type': 'bar',
# 'stack': 'x',
'name': "WARNING"
}
error = {
'data': [],
'type': 'bar',
# 'stack': 'x',
'name': "ERROR",
}
if year == the_year:
while flag:
try:
line = str(next(data)) # 拿到每行数据
if line.startswith('&&'):
n, level, time, module, message = line.split('&&')
m = time.split('-')[1]
if level == 'WARNING':
warning_div[int(m)] = warning_div[int(m)] + 1
else:
error_div[int(m)] = error_div[int(m)] + 1
except StopIteration:
# 如果生成器读到文件最后,继续next就会报错,捕获后就退出循环
flag = False
for v in warning_div.values():
warn['data'].append(v)
for v in error_div.values():
error['data'].append(v)
datas = [warn, error]
mon_lis = [f'{i}月' for i in mon_lis]
return ApiResponse(data=datas, year=year_lis, mon_lis=mon_lis)
else:
year_obj = models.YearLogData.objects.filter(year=str(year)).first()
if year_obj:
mon_data = models.DetalLogdata.objects.filter(year=year_obj).order_by('order')
ser = serializers.DeatailLogDataViewSerialize(instance=mon_data, many=True)
mount_set = []
for div in ser.data:
if div['type'] == 'WARNING':
warn['data'].append(div['count'])
mount_set.append(div['mount'])
else:
error['data'].append(div['count'])
datas = [warn, error]
return ApiResponse(data=datas, mon_lis=list(mount_set), year=year_lis)
return ApiResponse(code=404, data='没有相应的数据', year=year_lis)
# 管理员更新用户信息
class UpdateUserView(GenericViewSet, DestroyModelMixin, UpdateModelMixin):
queryset = models.User.objects
serializer_class = serializers.UpdateUserView
permission_classes = [permiss.SuperAdminPermission]
# 更新用户信息
def update(self, request, *args, **kwargs):
id = kwargs.get('pk')
role = request.data.get('role')
part = models.Part.objects.get(id=request.data.get('part_f'))
position = models.Position.objects.get(id=request.data.get('position'))
desc = position.name # 用户的描述信息
if role == 3: # 更新权限是经理,职位也是经理
if '经理' in position.name:
user = models.User.objects.filter(part=part, role=3).last()
if user: # 该部门已经存在经理了。
if int(id) == user.id: # 当前修改的人就是经理,则可以修改
models.User.objects.filter(id=id).update(desc=desc, **request.data)
return ApiResponse(code=100)
else:
return ApiResponse(code=500, error='该部门已经存在经理了!!')
else: # 该部门没有经理,直接更新
models.User.objects.filter(id=id).update(desc=desc, **request.data)
# 部门经理改变了,part表中的经理字段外键也要修改
models.Part.objects.filter(id=part.id).update(manager_id=id)
return ApiResponse(code=100)
else:
return ApiResponse(code=500, error='权限是经理,职位必须是部门经理!!')
elif role in [1, 2]:
if part.name == '老板部':
# 权限是超级管理有员或管理员,所在部门必须是老板部
models.User.objects.filter(id=id).update(desc=desc, **request.data)
return ApiResponse(code=100)
return ApiResponse(code=500, error='权限是管理员,必须属于老板部')
elif role == 4:
if '经理' in position.name or part.name == '老板部':
return ApiResponse(code=500, error='权限与职业不匹配!!')
models.User.objects.filter(id=id).update(desc=desc, **request.data)
return ApiResponse(code=100)
else:
return ApiResponse(code=500, error='携带的权限不存在')
# 删除单个用户
def destroy(self, request, *args, **kwargs):
id = kwargs.get('pk')
if id:
try:
user = models.User.objects.get(id=id, is_active=True)
name = user.name
if user:
user.is_active = False
user.is_show = False
user.save()
return ApiResponse(code=100, name=name)
return ApiResponse(code=404, msg='正在删除不存在的用户')
except Exception as e:
return ApiResponse(code=500, msg='删除失败')
return ApiResponse(code=404, msg='正在删除不存在的用户')
# 用户修改密码
class EditPasswordView(GenericViewSet, UpdateModelMixin):
queryset = models.User.objects
serializer_class = serializers.EditPasswordViewSeriazer
@action(methods=['patch'], detail=False)
def password(self, request):
ser = serializers.EditPasswordViewSeriazer(data=request.data, context={'request': request})
if ser.is_valid():
return ApiResponse(code=100, msg='修改密码成功')
else:
return ApiResponse(code=500, msg=str(ser.errors))
#拿到实习转正需要的部门和职位的关系库
class PartForPositive(GenericViewSet,ListModelMixin):
def list(self, request, *args, **kwargs):
part = request.query_params.get('id')
position = models.Position.objects.filter(Q(part_id=part)&~Q(name__contains='实习生'))
ser = serializers.PartForPositiveSerializer(instance=position,many=True)
return ApiResponse(code=100,data=ser.data)
class PositiveView(GenericViewSet,ListModelMixin,UpdateModelMixin):
pagination_class = PageNumberEvectionPaginations
serializer_class = serializers.PositiveSerializer
def list(self, request, *args, **kwargs):
queryset = models.User.objects.filter(desc__contains='实习生').order_by('id')
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return ApiResponse(serializer.data)
def update(self, request, *args, **kwargs):
try:
user = models.User.objects.get(id=request.data.get('id'))
position = models.Position.objects.get(id=request.data.get('position'))
user.position=position
user.desc=position.name#更改用户描述
user.save()
return ApiResponse()
except Exception as e:
print(e)
return ApiResponse(code=500,error='无此数据,无法操作')
五、论文参考
六、系统视频
基于Python的在线政务服务中心
结语
大家可以帮忙点赞、收藏、关注、评论啦~
源码获取:私信我