基于Python的在线政务服务中心

作者主页: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的在线政务服务中心

结语

大家可以帮忙点赞、收藏、关注、评论啦~
源码获取:私信我

精彩专栏推荐⬇⬇⬇
Java项目
Python项目
安卓项目
微信小程序项目

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值