zoukankan      html  css  js  c++  java
  • 工单系统之用户模块

    1 Django端

    • 历经千辛万苦,终于排除所有用户模块的bugT.T

    1.1 settings.py

    """
    Django settings for opwf project.
    
    Generated by 'django-admin startproject' using Django 2.0.13.
    
    For more information on this file, see
    https://docs.djangoproject.com/en/2.0/topics/settings/
    
    For the full list of settings and their values, see
    https://docs.djangoproject.com/en/2.0/ref/settings/
    """
    import datetime
    import os, sys
    
    # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
    
    
    # Quick-start development settings - unsuitable for production
    # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/
    
    # SECURITY WARNING: keep the secret key used in production secret!
    SECRET_KEY = 'uorj1ni^mnut@wo@c%)iv)%5=8dxlml4-j0!f3b%4#f*8a5)3t'
    
    # SECURITY WARNING: don't run with debug turned on in production!
    DEBUG = True
    
    ALLOWED_HOSTS = ['*']
    
    
    # Application definition
    
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'rest_framework',
        'corsheaders',
        'user.apps.UserConfig',
        'workflow.apps.WorkflowConfig',
        'workerorder.apps.WorkerorderConfig',
        # 'jwt',
        # 'rest_framework_jwt',
        # 'rest_framework.authentication'
    
    ]
    
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'corsheaders.middleware.CorsMiddleware',
        # 'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    
    ROOT_URLCONF = 'opwf.urls'
    CORS_ORIGIN_ALLOW_ALL = True
    
    CORS_ORIGIN_WHITELIST = (
        'http://127.0.0.1:8080',
        'http://localhost:8080',
    )
    CORS_ALLOW_CREDENTIALS = True
    
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]
    
    WSGI_APPLICATION = 'opwf.wsgi.application'
    
    
    # Database
    # https://docs.djangoproject.com/en/2.0/ref/settings/#databases
    
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'opwf_db',
            'USER': 'root',
            'PASSWORD': '1',
            'HOST': '127.0.0.1',
            'PORT': '3306'
        }
    }
    
    
    # Password validation
    # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators
    
    REST_FRAMEWORK = {
        # 文档报错: AttributeError: ‘AutoSchema’ object has no attribute ‘get_link’
        # 用下面的设置可以解决
        'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema',
        # 默认设置是:
        # 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.openapi.AutoSchema',
    
        # 异常处理器
        # 'EXCEPTION_HANDLER': 'user.utils.exception_handler',
    
        # Base API policies      默认渲染器类
        'DEFAULT_RENDERER_CLASSES': [
            'rest_framework.renderers.JSONRenderer',
            'rest_framework.renderers.BrowsableAPIRenderer',
        ],
        # 默认解析器类
        'DEFAULT_PARSER_CLASSES': [
            'rest_framework.parsers.JSONParser',
            'rest_framework.parsers.FormParser',
            'rest_framework.parsers.MultiPartParser'
        ],
        # 1.认证器(全局)
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'rest_framework_jwt.authentication.JSONWebTokenAuthentication',  # 在 DRF中配置JWT认证
            # 'rest_framework.authentication.SessionAuthentication',  # 使用session时的认证器
            # 'rest_framework.authentication.BasicAuthentication'  # 提交表单时的认证器
        ],
    
        # 2.权限配置(全局): 顺序靠上的严格
        'DEFAULT_PERMISSION_CLASSES': [
            # 'rest_framework.permissions.IsAdminUser',  # 管理员可以访问
            # 'rest_framework.permissions.IsAuthenticated',  # 认证用户可以访问
            # 'rest_framework.permissions.IsAuthenticatedOrReadOnly',  # 认证用户可以访问, 否则只能读取
            'rest_framework.permissions.AllowAny',  # 所有用户都可以访问
        ],
        # 3.限流(防爬虫)
        'DEFAULT_THROTTLE_CLASSES': [
            'rest_framework.throttling.AnonRateThrottle',
            'rest_framework.throttling.UserRateThrottle',
        ],
        # 3.1限流策略
        # 'DEFAULT_THROTTLE_RATES': {
        #     'user': '100/hour',  # 认证用户每小时100次
        #     'anon': '300/day',  # 未认证用户每天能访问3次
        # },
    
        'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'rest_framework.negotiation.DefaultContentNegotiation',
        'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata',
        'DEFAULT_VERSIONING_CLASS': None,
    
        # 4.分页(全局):全局分页器, 例如 省市区的数据自定义分页器, 不需要分页
        # 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
        # # 每页返回数量
        # 'PAGE_SIZE': 3,
        # 5.过滤器后端
        'DEFAULT_FILTER_BACKENDS': [
            'django_filters.rest_framework.DjangoFilterBackend',
            # 'django_filters.rest_framework.backends.DjangoFilterBackend', 包路径有变化
        ],
    
        # 5.1过滤排序(全局):Filtering 过滤排序
        'SEARCH_PARAM': 'search',
        'ORDERING_PARAM': 'ordering',
    
        'NUM_PROXIES': None,
    
        # 6.版本控制:Versioning  接口版本控制
        'DEFAULT_VERSION': None,
        'ALLOWED_VERSIONS': None,
        'VERSION_PARAM': 'version',
    
        # Authentication  认证
        # 未认证用户使用的用户类型
        'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser',
        # 未认证用户使用的Token值
        'UNAUTHENTICATED_TOKEN': None,
    
        # View configuration
        'VIEW_NAME_FUNCTION': 'rest_framework.views.get_view_name',
        'VIEW_DESCRIPTION_FUNCTION': 'rest_framework.views.get_view_description',
    
        'NON_FIELD_ERRORS_KEY': 'non_field_errors',
    
        # Testing
        'TEST_REQUEST_RENDERER_CLASSES': [
            'rest_framework.renderers.MultiPartRenderer',
            'rest_framework.renderers.JSONRenderer'
        ],
        'TEST_REQUEST_DEFAULT_FORMAT': 'multipart',
    
        # Hyperlink settings
        'URL_FORMAT_OVERRIDE': 'format',
        'FORMAT_SUFFIX_KWARG': 'format',
        'URL_FIELD_NAME': 'url',
    
        # Encoding
        'UNICODE_JSON': True,
        'COMPACT_JSON': True,
        'STRICT_JSON': True,
        'COERCE_DECIMAL_TO_STRING': True,
        'UPLOADED_FILES_USE_URL': True,
    
        # Browseable API
        'HTML_SELECT_CUTOFF': 1000,
        'HTML_SELECT_CUTOFF_TEXT': "More than {count} items...",
    
        # Schemas
        'SCHEMA_COERCE_PATH_PK': True,
        'SCHEMA_COERCE_METHOD_NAMES': {
            'retrieve': 'read',
            'destroy': 'delete'
        },
    
        # 'Access-Control-Allow-Origin':'http://localhost:8080',
        # 'Access-Control-Allow-Credentials': True
    
    }
    
    AUTH_PASSWORD_VALIDATORS = [
        {
            'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
        },
    ]
    
    
    # Internationalization
    # https://docs.djangoproject.com/en/2.0/topics/i18n/
    
    LANGUAGE_CODE = 'zh-hans'
    
    TIME_ZONE = 'Asia/Shanghai'
    
    USE_I18N = True
    
    USE_L10N = True
    
    USE_TZ = False
    
    
    # Static files (CSS, JavaScript, Images)
    # https://docs.djangoproject.com/en/2.0/howto/static-files/
    
    STATIC_URL = '/static/'
    AUTH_USER_MODEL = 'user.User'
    
    # jwt载荷中的有效期设置
    JWT_AUTH = {
        # 1.token前缀:headers中 Authorization 值的前缀
        'JWT_AUTH_HEADER_PREFIX': 'JWT',
        # 2.token有效期:一天有效
        'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
        # 3.刷新token:允许使用旧的token换新token
        'JWT_ALLOW_REFRESH': True,
        # 4.token有效期:token在24小时内过期, 可续期token
        'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(hours=24),
        # 5.自定义JWT载荷信息:自定义返回格式,需要手工创建
        'JWT_RESPONSE_PAYLOAD_HANDLER': 'user.utils.jwt_response_payload_handler',
    }
    
    

    1.2 models.py

    from django.db import models
    from django.contrib.auth.models import AbstractUser
    
    # Create your models here.
    
    
    
    class User(AbstractUser):
        '''
        username:用户名
        password:密码
        mobile:手机号
        email:邮箱
        '''
        username = models.CharField(max_length=30, unique=True)
        # 写上 unique=True 就可以指定唯一,验证字段的时候自动验证
        password = models.CharField(max_length=256)
        mobile = models.CharField(max_length=11)
        email = models.CharField(max_length=30)
        token = models.CharField(max_length=256, default='')
        weixin = models.CharField(max_length=30, null=True)
        date_joined = models.DateField(auto_now_add=True)
    
        class Meta:
            db_table = 'user_user'
            verbose_name = '用户表'
            verbose_name_plural = verbose_name
    
    
    class Role(models.Model):
        '''
        name:角色名称
        description:描述
        '''
        zh_name = models.CharField(max_length=30)
        en_name = models.CharField(max_length=30)
        description = models.TextField()
    
        class Meta:
            db_table = 'user_role'
            verbose_name = '角色表'
            verbose_name_plural = verbose_name
    
    
    
    class UserRole(models.Model):
        user = models.ForeignKey(User, on_delete=models.CASCADE)
        role = models.ForeignKey(Role, on_delete=models.CASCADE)
    
        class Meta:
            db_table = 'user_userrole'
            verbose_name = '用户角色表'
            verbose_name_plural = verbose_name
    

    1.3 serializers.py

    # -*- coding: utf-8 -*-
    from rest_framework import serializers
    from rest_framework_jwt.serializers import jwt_payload_handler
    from rest_framework_jwt.settings import api_settings
    
    from user.models import User, UserRole, Role
    
    
    class UserModelSerializer(serializers.ModelSerializer):
        is_superuser = serializers.CharField(default=0)
        roles = serializers.SerializerMethodField(required=False)
        class Meta:
            model = User
            fields = '__all__'
        def create(self, data):
            username = data.get('username', '')
            password = data.get('password', '')
            mobile = data.get('mobile', '')
            email = data.get('email', '')
            weixin = data.get('weixin', '')
            user = User(username=username, email=email, mobile=mobile, weixin=weixin)
            user.set_password(password)
            user.save()
            return user
    
        def get_roles(self, row):
            roles_json = UserRole.objects.filter(user=row).values('role__id', "role__zh_name")
            print('111', roles_json)
            print('222', list(roles_json))
            print(type(list(roles_json)))
            return list(roles_json)
    
        def get_serializer_class(self):
            return UserModelSerializer
    
    class UserSerializer(serializers.Serializer):
        id = serializers.IntegerField()
        username = serializers.CharField()
        password = serializers.CharField()
        mobile = serializers.CharField()
        email = serializers.EmailField()
        weixin = serializers.CharField()
        token = serializers.CharField(read_only=True)
    
        def create(self, data):
            username = data.get('username', '')
            password = data.get('password', '')
            mobile = data.get('mobile', '')
            email = data.get('email', '')
            weixin = data.get('weixin', '')
    
            user = User(username=username, email=email, mobile=mobile, weixin=weixin)
            user.set_password(password)
            user.save()
            # 补充生成记录登录状态的token
            jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
            jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)
            user.token = token
            return user
    
    class UserRoleSerializer(serializers.ModelSerializer):
        class Meta:
            model = UserRole
            fields = '__all__'
    
    class RoleSerializer(serializers.ModelSerializer):
        class Meta:
            model = Role
            fields = "__all__"
    

    1.4 views.py

    import datetime
    import random
    
    from django.contrib.auth.hashers import make_password
    from django.shortcuts import render
    
    # Create your views here.
    from rest_framework import viewsets
    from rest_framework.pagination import PageNumberPagination
    from rest_framework.response import Response
    from rest_framework.views import APIView
    
    from user.models import User, Role, UserRole
    from user.serializers import UserSerializer, UserModelSerializer, RoleSerializer, UserRoleSerializer
    
    
    # 分页(局部):自定义分页器 局部
    class PageNum(PageNumberPagination):
        page_size = 4                           # 每页显示多少条
        page_size_query_param = 'page_size'     # 查询字符串中代表每页返回数据数量的参数名, 默认值: None
        page_query_param = 'page'               # 查询字符串中代表页码的参数名, 有默认值: page
        max_page_size = None                    # 最大页码数限制
    
    
    
    class UserViewSet(viewsets.ModelViewSet):
        queryset = User.objects.all()
        serializer_class = UserModelSerializer
        filter_fields = {"username", 'mobile', 'weixin', 'email'}
        pagination_class = PageNum  # 注意不是列表(只能有一个分页模式)
    
        def perform_update(self, serializer):
            user_obj = serializer.save()
            # 原有的serializer反序列化添加
            roles = self.request.data.get('roles')
            user_obj.userrole_set.all().delete()
            for role_id in roles:
                userrole = UserRole.objects.create(user=user_obj, role_id=role_id)
        def get_serializer_class(self):
            print('action------->', self.action)
            return UserModelSerializer
    
    class UserGetViewSet(viewsets.ModelViewSet):
        queryset = User.objects.all()
        serializer_class = UserSerializer
    
    class RoleViewSet(viewsets.ModelViewSet):
        queryset = Role.objects.all()
        serializer_class = RoleSerializer
        filter_fields = {"zh_name"}
        pagination_class = PageNum  # 注意不是列表(只能有一个分页模式)
    
    class RoleGetViewSet(viewsets.ModelViewSet):
        # 用于角色查看接口(没有分页的那种)
        queryset = Role.objects.all()
        serializer_class = RoleSerializer
    
    
    class RegisterView(APIView):
        def post(self, request):
            username = request.data.get('username')
            password = request.data.get('password')
            password_new = request.data.get('password_new')
            role = request.data.get('roles')
            print(role)
            if not all([username, password, password_new]):
                return Response(
                    {'msg': '信息不全', 'code': 400}
                )
            if password != password_new:
                return Response(
                    {'code': 400, 'msg':'两次登录密码不一致'}
                )
            user_serializer = UserSerializer(data=request.data)
            if user_serializer.is_valid():
                user_serializer.save()
                user_obj = User.objects.filter(username=username).first()
                print(user_obj)
                new_list = []
                for i in role:
                    role_obj = Role.objects.filter(id=i).first()
                    # UserRole.objects.create(user=user_obj, role=role_obj)
                    # UserRole.objects.create(user_id=user_obj.id, role_id=role_obj.id)
                    new_list.append((UserRole(user=user_obj, role=role_obj)))
                UserRole.objects.bulk_create(new_list)
                return Response(
                    {'msg': '注册成功', 'code': 200, 'data':user_serializer.data}
                )
    
            return Response(
                {'msg': '注册失败', 'error': user_serializer.errors }
            )
    

    1.5 urls.py

    # -*- coding: utf-8 -*-
    
    from django.urls import path
    from rest_framework.routers import DefaultRouter
    from rest_framework_jwt.views import obtain_jwt_token
    
    from user import views
    
    router = DefaultRouter()
    router.register(r'user', views.UserViewSet)
    router.register(r'user_get', views.UserGetViewSet)
    router.register(r'role', views.RoleViewSet)
    router.register(r'role_get', views.RoleGetViewSet)
    
    urlpatterns = [
        path('login/', obtain_jwt_token),
        path('register/', views.RegisterView.as_view()),
    ]
    
    urlpatterns += router.urls
    

    1.6 utils.py

    # -*- coding: utf-8 -*-
    def jwt_response_payload_handler(token, user=None, request=None, role=None):
        """
            自定义jwt认证成功返回数据
            :token 返回的jwt
            :user 当前登录的用户信息[对象]
            :request 当前本次客户端提交过来的数据
            :role 角色
        """
        if user.first_name:
            name = user.first_name
        else:
            name = user.username
            return {
                'authenticated': 'true',
                 'id': user.id,
                 "role": role,
                 'name': name,
                 'username': user.username,
                 'email': user.email,
                 'token': token,
            }
    

    1.7 MyBaseModel.py

    # -*- coding: utf-8 -*-
    from django.db import models
    
    class BaseModel(models.Model):
        is_delete = models.BooleanField('是否刪除', default=0)
        create_time = models.DateField('创建时间', auto_now_add=True, null=True)
        update_time = models.DateField('更新时间', auto_now=True, null=True)
    
        class Meta:
            abstract = True
    
    class BaseModelFlow(models.Model):
        name = models.CharField('名称', max_length=60)
        description = models.TextField('描述')
    
        class Meta:
            abstract = True
    

    1.8 主路由urls.py

    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('user/', include('user.urls')),
        path('workflow/', include('workflow.urls')),
        path('workerorder/', include('workerorder.urls')),
    ]
    
    

    2 Vue端

    2.1 @/components/layout/Header.vue

    <template>
            <div>
              <h3 style="margin-top:20px">
               
              欢迎你
               <a-icon type="smile" theme="outlined" style="font-size:20px;color:pink"/>&ensp;
              {{username}}
                <a-icon type="fire" style="font-size:25px;color:pink"/>&ensp;
              </h3>
            </div>
    </template>
    <script>
    export default{
        data(){
            return{
              username:localStorage.getItem('username')
            }
        }
    }
    </script>
    
    

    2.2 @/components/layout/Home.vue

    <template>
             <div id="components-layout-demo-basic" style="">
                <a-layout>
                    <a-layout-sider style="height:250px;150px">
                        <LeftMenu style="margin-left:-55px"></LeftMenu>
                        <!-- 以组件发昂视导入左侧菜单 -->
                    </a-layout-sider>
                    <a-layout>
    
                        <a-layout-header  style="height:100px;500px;background:rgb(253,234,254)">
                            <Header/>
                            <!-- 导入头部 -->
                        </a-layout-header>
                        
                            <div style="margin-left:100px">
                                <!-- 这里的 router-view 是绑定的路由 -->
                                <router-view></router-view>
                            </div>
                            
                    </a-layout>
    
                </a-layout>
            </div>
    </template>
    
    <script>
    // 导入组件
    import LeftMenu from '@/components/layout/LeftMenu'
    import Header from '@/components/layout/Header'
    export default {
        // 注册组件
        components:{
            LeftMenu,
            Header
        },
        data() {
            
            return {
    
            }
        },
        methods: {
    
        },
        created() {
    
        }
    }
    </script>
    
    <style scoped>
    #components-layout-demo-basic {
      text-align: center;
    }
    #components-layout-demo-basic .ant-layout-header {
      background: white;
    }
    #components-layout-demo-basic .ant-layout-footer {
      background: rgb(253,234,254);
      color: rgb(253,234,254);
    }
    #components-layout-demo-basic .ant-layout-footer {
      line-height: 1.5;
    }
    #components-layout-demo-basic .ant-layout-sider {
      background: rgb(253,234,254);
      color: rgb(253,234,254);
      line-height: 120px;
    }
    #components-layout-demo-basic .ant-layout-content {
      background: white;
      color: white;
      min-height: 120px;
      line-height: 120px;
    }
    .ant-layout.ant-layout-has-sider{
      1700px;
      height: 800px;
      background:rgb(253,234,254)
    }
    .ant-layout{
      background:rgb(253,234,254);
      800px
    }
    </style>
    
    

    2.3 @/components/layout/LeftMenu.vue

    <template>
      <div>
        <a-switch :default-checked="false" @change="changeMode" style="margin-top:70px"/>&emsp;
        <br>
        <a-menu
          style=" 300px;background:rgb(253,234,254)"
          :default-selected-keys="['1']"
          :default-open-keys="['sub1']"
          :mode="mode"
          :theme="theme"
          @click="handleClick"
          
        >
        <!-- 必须定义click方法,handleClick是用来跳转路由的,内置毁掉参数e,包括传递上去的key路由地址 -->
          <a-sub-menu >
            <span slot="title">
              <a-icon type="user" />
              <span>用户模块</span>
            </span>
              
              <a-menu-item key="usermanage" title="用户信息管理" style="background:rgb(253,234,254)">
                信息管理
              </a-menu-item>
              <!-- key是路由地址 -->
    
              <a-menu-item key="rolemanage" title="工单模板" style="background:rgb(253,234,254)">
                角色管理
              </a-menu-item>
    
    
           </a-sub-menu>
          
    
          <a-menu-item key="baidu">
            <a-icon type="calendar" />
            百度翻译
          </a-menu-item>
          <a-sub-menu key="workflow" style="background:rgb(253,234,254)">
            <span slot="title">
              <a-icon type="appstore" />
              <span>模板管理</span>
            </span>
              
              <a-menu-item key="flowtype" title="工单分类" style="background:rgb(253,234,254);">
                模板分类
              </a-menu-item>
    
              <a-menu-item key="flowconf" title="工单模板" style="background:rgb(253,234,254)">
                新建模板
              </a-menu-item>
    
           </a-sub-menu>
        
          <a-sub-menu key="workorder">
            <span slot="title"><a-icon type="setting" /><span>工单管理</span></span>
                  
              <a-menu-item key="workorder" style="background:rgb(253,234,254)">
              实例化工单
              </a-menu-item>
    
              <a-menu-item key="suborder"  style="background:rgb(253,234,254)">
              实例化子工单
              </a-menu-item>
    
          </a-sub-menu>
        </a-menu>
      </div>
    </template>
    <script>
    export default {
      data() {
        return {
          mode: 'inline',
          theme: 'light',
          current: '1'
        };
      },
      methods: {
        changeMode(checked) {
          this.mode = checked ? 'vertical' : 'inline';
        },
        changeTheme(checked) {
          this.theme = checked ? 'dark' : 'light';
        },
         handleClick(e) {
          this.current = e.key;
          console.log(e.domEvent)
          this.$router.push({path:this.current});
          // click方法默认回调参数中的 key,所以 e.key就是传递来的路由
        },
      },
    };
    </script>
    <style>
    .a-menu{
      background:rgb(253,234,254);
         550px;
    }
    .ul{
      background:rgb(253,234,254)
    }
    .ant-menu-submenu > .ant-menu{
      background-color: rgb(253,234,254);
    
    }
    </style>
    
    
    

    2.4 @/http/apis.js

    //将我们http.js中封装好的  get,post.put,delete,patch  导过来
    import { axios_get, axios_post, axios_delete, axios_put, axios_patch } from './index.js'
    
    
    
    
    //按照格式确定方法名
    export const user_login = P => axios_post("/user/login/", P)  // 用户登录
    
    // 用户模块
    // 用户信息管理
    export const get_userlist = P => axios_get('/user/user/?page='+P, P)            // 获取用户列表
    export const get_userlist_new = P => axios_get('user/user_get/', P)             // 获取用户列表(不包含分页的接口)
    export const add_user = P => axios_post('/user/register/', P)                   // 注册新用户
    export const search_for = P => axios_get('user/user/', P)                       // 根据用户名查找指定用户信息并展示
    export const delete_user = P => axios_delete('/user/user/' + P + '/')           // 根据获取到的用户id删除用户信息
    export const update_user = P => axios_put('/user/user/'+ P.id +'/', P)          // 根据用户id和提交来的数据修改用户信息
    
    // 角色管理
    export const get_rolelist = P => axios_get('/user/role/?page='+P, P)            // 获取角色列表
    export const get_rolelist_new = P => axios_get('/user/role_get/', P)            // 获取角色列表(不包含分页的接口)
    export const add_role = P => axios_post('/user/role/', P)                       // 注册新角色
    export const search_for_role = P => axios_get('user/role/', P)                  // 根据角色名查找指定角色信息并展示
    export const delete_role = P => axios_delete('/user/role/' + P + '/')           // 根据获取到的角色id删除角色信息
    export const update_role = P => axios_put('/user/role/'+ P.id +'/', P)          // 根据角色id和提交来的数据修改角色信息
    
    // 工单模块---分类工单
    export const get_flowtypelist = P => axios_get('/workflow/flowtype/?page='+P, P)            // 获取模板分类列表
    export const get_flowtypelist_new = P => axios_get('/workflow/flowtype_get/', P)            // 获取模板分类列表(不含分页)
    export const add_flowtype = P => axios_post('/workflow/flowtype/', P)                       // 创建新模板分类
    export const search_for_flowtype = P => axios_get('/workflow/flowtype/', P)                  // 根据模板分类名查找指定模板分类信息并展示
    export const delete_flowtype = P => axios_delete('/workflow/flowtype/' + P + '/')           // 根据获取到的模板分类id删除模板分类信息
    export const update_flowtype = P => axios_put('/workflow/flowtype/'+ P.id +'/', P)          // 根据模板分类id和提交来的数据修改模板分类信息
    
    // 工单模块---工单模板
    export const get_flowconflist = P => axios_get('/workflow/flowconf/?page='+P, P)            // 获取工单模板列表
    export const get_flowconflist_new = P => axios_get('/workflow/flowconf_get/', P)            // 获取工单模板列表(不含分页)
    export const add_flowconf = P => axios_post('/workflow/flowconf/', P)                       // 创建新工单模板
    export const search_for_flowconf = P => axios_get('/workflow/flowconf/', P)                  // 根据工单模板名查找指定工单模板信息并展示
    export const delete_flowconf = P => axios_delete('/workflow/flowconf/' + P + '/')           // 根据获取到的工单模板id删除工单模板信息
    export const update_flowconf = P => axios_put('/workflow/flowconf/'+ P.id +'/', P)          // 根据工单模板id和提交来的数据修改工单模板信息
    
    // 工单模块---配置审批流
    export const get_approveconflist = P => axios_get('/workflow/approveconf/?page='+P, P)            // 获取配置审批流列表
    export const add_approveconf = P => axios_post('/workflow/approveconf/', P)                       // 配置新审批流
    export const delete_approveconf = P => axios_delete('/workflow/approveconf/' + P + '/')           // 根据审批流id删除审批流信息
    export const update_approveconf = P => axios_put('/workflow/approveconf/'+ P.id +'/', P)          // 根据审批流id和提交来的数据修改审批流信息
    

    2.5 @/http/index.js

    import axios from 'axios'
    
    // 第一步:设置axios
    axios.defaults.baseURL = "http://192.168.56.100:1594/"
    
    //全局设置网络超时
    axios.defaults.timeout = 10000;
    
    //设置请求头信息
    axios.defaults.headers.post['Content-Type'] = 'application/json';
    axios.defaults.headers.put['Content-Type'] = 'application/json';
    
    
    // 第二:设置拦截器
    /**
     * 请求拦截器(当前端发送请求给后端前进行拦截)
     * 例1:请求拦截器获取token设置到axios请求头中,所有请求接口都具有这个功能
     * 例2:到用户访问某一个页面,但是用户没有登录,前端页面自动跳转 /login/ 页面
     */
    axios.interceptors.request.use(
        config => {
            // 每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了
            const token = localStorage.getItem("token")
                // console.log(token)
            if (token) {
                config.headers.Authorization = 'JWT ' + token
            }
            return config;
        },
        error => {
            return Promise.error(error);
        })
    
    axios.interceptors.response.use(
        // 请求成功,因为 API返回的状态码有多个,所以一定要在这里写上,不然会无法访问页面
        res => res.status === 200 || 201 || 204 ? Promise.resolve(res) : Promise.reject(res),
        // 请求失败
        error => {
            if (error.response) {
                // 判断一下返回结果的status == 401?  ==401跳转登录页面。  !=401passs
                // console.log(error.response)
                if (error.response.status === 401) {
                    // 跳转不可以使用this.$router.push方法、
                    // this.$router.push({path:'/login'})
                    window.location.href = "http://127.0.0.1:8080/"
                } else {
                    // errorHandle(response.status, response.data.message);
                    return Promise.reject(error.response);
                }
                // 请求已发出,但是不在2xx的范围
            } else {
                // 处理断网的情况
                // eg:请求超时或断网时,更新state的network状态
                // network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
                // 关于断网组件中的刷新重新获取数据,会在断网组件中说明
                // store.commit('changeNetwork', false);
                return Promise.reject(error.response);
            }
        });
    
    
    // 第三:封装axios请求
    // 3.1 封装get请求
    export function axios_get(url, params) {
        return new Promise(
            (resolve, reject) => {
                axios.get(url, {params:params})
                    .then(res => {
                        // console.log("封装信息的的res", res)
                        resolve(res.data)
                    }).catch(err => {
                        reject(err.data)
                    })
            }
        )
    }
    
    // 3.2 封装post请求
    export function axios_post(url, data) {
        return new Promise(
            (resolve, reject) => {
                // console.log(data)
                axios.post(url, JSON.stringify(data))
                    .then(res => {
                        // console.log("封装信息的的res", res)
                        resolve(res.data)
                    }).catch(err => {
                        reject(err.data)
                    })
            }
        )
    }
    
    // 3.3 封装put请求
    export function axios_put(url, data) {
        return new Promise(
            (resolve, reject) => {
                // console.log(data)
                axios.put(url, JSON.stringify(data))
                    .then(res => {
                        // console.log("封装信息的的 res", res)
                        resolve(res.data)
                    }).catch(err => {
                        reject(err.data)
                    })
            }
        )
    }
    
    // 3.4 封装patch请求(可用于局部修改)
    
    export function axios_patch(url, data) {
        return new Promise(
            (resolve, reject) => {
                // console.log(data)
                axios.patch(url, JSON.stringify(data))
                    .then(res => {
                        // console.log("封装信息的的res", res)
                        resolve(res.data)
                    }).catch(err => {
                        reject(err.data)
                    })
            }
        )
    }
    
    // 3.5 封装delete请求
    export function axios_delete(url, data) {
        return new Promise(
            (resolve, reject) => {
                // console.log(data)
                axios.delete(url, { params: data })
                    .then(res => {
                        // console.log("封装信息的的res", res)
                        resolve(res.data)
                    }).catch(err => {
                        // reject(err.data)
                    })
            }
        )
    }
    

    2.6 @/views/user-manage/components/BreadCrumb.vue

    <template>
        <div>
            <a-breadcrumb>
                <br>
                <a-breadcrumb-item href="">
                <a-icon type="home" />
                </a-breadcrumb-item>
    
                <a-breadcrumb-item href="">
                <a-icon type="user" />
                <span>首页</span>
    
                </a-breadcrumb-item>
                <a-breadcrumb-item>
                用户模块
                </a-breadcrumb-item>
                <a-breadcrumb-item>
                信息管理页面
                </a-breadcrumb-item>
            </a-breadcrumb>
        </div>
    </template>
    
    <script>
    export default {
        name:"BreadCrumb",
        data() {
            return {
    
            }
        },
        methods: {
    
        },
        created() {
    
        }
    }
    </script>
    
    <style scoped>
    
    </style>
    

    2.7 @/views/user-manage/components/EditForm.vue

    <template>
        <div>
            <a-modal
            title="Please write now."
            :visible="visible"
            @ok="handleOk"
            @cancel="handleCancel"
            >
            <!-- @ok控制按钮ok -->
            <!-- @cancel控制按钮cancel -->
                <p v-if="userList.id">UserName:
                    <a-input 
                    style="380px;float:right" 
                    placeholder="username" 
                    v-model="userList.username"
                    disabled="disabled"
                    ></a-input>                
                </p>
                <p v-else>UserName:
                    <a-input 
                    style="380px;float:right" 
                    placeholder="username" 
                    v-model="userList.username"
                    ></a-input>
                </p>
                <br>
                <div v-if="userList.id">
    
                </div>
                <div v-else>
                <p>PassWord:
                    <a-input
                        v-decorator="[
                            'password',
                            { rules: [{ required: true, message: 'Please input your Password!' }] },
                        ]"
                        type="password"
                        placeholder="Password"
                        style="380px;float:right"
                        v-model="userList.password"
                        :disabled = 'false'
                    >
                        <a-icon slot="prefix" type="lock" style="color:rgba(0,0,0,.25)" />
                    </a-input>
                </p>
                <br>
                <p>PassWord Again:
                    <a-input
                        v-decorator="[
                            'password',
                            { rules: [{ required: true, message: 'Please input your Password!' }] },
                        ]"
                        type="password"
                        placeholder="Password"
                        style="340px;float:right"
                        v-model="userList.password_new"
                    >
                        <a-icon slot="prefix" type="lock" style="color:rgba(0,0,0,.25)" />
                    </a-input>
                </p>
                </div>
                <br>
                <p>Email:
                    <a-input style="410px;float:right" placeholder="Email" v-model="userList.email"></a-input>
                </p>
                <br>
                <p>Mobile:
                    <a-input style="410px" placeholder="Mobile" v-model="userList.mobile"></a-input>
                </p>
                <br>
                <p>Weixin:
                    <a-input style="410px" placeholder="WeiXin" v-model="userList.weixin"></a-input>
                </p>
                <br>
                <p>Role:
                 <a-select
                    mode="multiple"               
                    style=" 410px; float:right"
                    placeholder="Please select"
                    @change="handleChange"
                    v-model="userList.roles"
                 >
                    <a-select-option v-for="i in roleList" :key="i.id" >
                    {{ i.zh_name }}
                    </a-select-option>
                </a-select>
                </p>
            </a-modal>
    
        </div>
    </template>
    
    <script>
    export default {
        props:['visible', 'userList', 'roleList'],
        data() {
            return {
            }
        },
        methods: {
            handleOk(e) {
                this.$emit('add', this.role)
                // add方法的调用一定要在关闭弹窗上面,否则方法不执行完毕没有办法关闭弹窗
                // 调用父组件中 add 方法            
                this.$emit('update:visible', false)
                // 把 visible 的值更新为 false,控制组件不显示
    
            },
            handleCancel(e) {
                this.$emit('update:visible', false)
                // 把 visible 的值更新为 false,控制组件不显示
            },
            handleChange(value) {
                // console.log(`selected ${value}`);
                console.log(value)
                this.userList.roles = value
            },
        },
        created() {
    
        }
    }
    </script>
    
    <style scoped>
    
    </style>
    

    2.8 @/views/user-manage/components/Pagination.vue

    <template>
      <div>
        <a-pagination
          show-quick-jumper
          :default-current="2"
          :pageSize = '4'
          :total="count"
          show-less-items
          @change="onChange"
          v-model="current"
    
        />
      </div>
    </template>
    
    <script>
    export default {
        props:[ 'count' ],
        data() {
            return {
                current:1
            }
        },
        methods: {
            
            onChange() {
                this.$emit('getPage', this.current)
        },
        },
        created() {
    
        }
    }
    </script>
    
    <style scoped>
    
    </style>
    

    2.9 @/views/user-manage/components/Search.vue

    <template>
        <div>
            <a-input-search placeholder="Input the username that you want to search for..." enter-button @search="onSearch" style="float:right;400px;" v-model="searchList.username"/>
        </div>
    </template>
    
    <script>
    export default {
        props:['searchList'],
        data() {
            return {
    
            } 
        },
        methods: {
            onSearch(){
                this.$emit('find')
                // 调用父组件中的find方法
            }
        },
        created() {
    
        }
    }
    </script>
    
    <style scoped>
    
    </style>
    

    2.10 @/views/user-manage/components/TableList.vue

    <template>
      <a-table 
        :columns="columns" 
        :data-source="userListGet" 
        :rowKey="(record,index)=>{return index}"
        :pagination= 'false'
        style="height:430px"
      >
      <!-- 带:的都是属性绑定,不可以更换名字,带 : 就是 js 环境 -->
        <!-- 不写:rowKey="(record,index)=>{return index}"浏览器会发出警告 -->
        <p slot="roles" slot-scope="roles">
          <a-tag
            v-for="role in roles"
            :key="role.id"
            color="pink"
          >
            {{ role.role__zh_name }}
          </a-tag>
        </p>
        <p slot="tags" slot-scope="text,tags,i">
          <!-- 加入操作的按钮! -->
          <a-button @click="delUser(text,tags,i)">删除</a-button>
          <a-button @click="updateUser(text,tags,i)">修改</a-button>
        </p>
      </a-table>
    </template>
    
    <script>
    const columns = [
        {
        title: 'ID',
        dataIndex: 'id',
        key: 'id',
        // ellipsis: true,
         50,
      },
      {
        title: 'UserName',
        dataIndex: 'username',
        key: 'username',
        scopedSlots: { customRender: 'username' },
         80,
      },
      {
        title: 'Email',
        dataIndex: 'email',
        key: 'email',
         150,
      },
      {
        title: 'Mobile',
        dataIndex: 'mobile',
        key: 'mobile',
        ellipsis: true,
         100,
      },
      {
        title: 'WeiXin',
        dataIndex: 'weixin',
        key: 'weixin',
        ellipsis: true,
         100,
      },
      {
        title: 'Date Joined',
        dataIndex: 'date_joined',
        key: 'date_joined',
        ellipsis: true,
         100,
      },
        {
        title: 'Roles',
        dataIndex: 'roles',
        key: 'roles',
        ellipsis: true,
         150,
        scopedSlots : { customRender: 'roles'}
        // 不写的话显示不了标签
      },
      {
        title:'操作',
        dataIndex: 'tags',
        key : 'tags',
         100,
        scopedSlots : { customRender: 'tags'}
        // scopedSlots: { customRender: 'tags' },一定不能少不然渲染不了html标签
    
      }
    
    ]
    
    import { delete_user } from '@/http/apis'
    export default {
      props:[ 'userListGet', 'userList'],
      data() {
        return {
          columns,
        }
      },
      methods:{
        get(){
            this.$emit('getUser')
            // 调用父组件中的获取用户列表的方法
        },
        delUser(text,tags,i){
          // 定义变量 isDel来控制 confirm,isDel==true执行的就是对话框的 ok,isDel==false执行的就是对话框的 false
            const isDel = confirm('你确定要删除' + tags.id)
            if(isDel==true){
              delete_user(tags.id).then(
              res=>{
                // 删除回调地址是  http://192.168.56.100:1594/id/
                this.get()
                alert('删除成功啦~')
              })
            }else{
                alert('有需要再叫我哈~')
            }
                 
        },
        updateUser(text,tags,i){
          const roleIds = []
          tags.roles.forEach(item => {
            roleIds.push(item.role__id)
          });
    
          this.userList.id = tags.id
          this.userList.username = tags.username
          this.userList.password = tags.password,
          this.userList.password_new = tags.password
          this.userList.email = tags.email
          this.userList.mobile = tags.mobile
          this.userList.weixin = tags.weixin
          // 传一个角色id的列表给父组件
          this.userList.roles = roleIds     
          this.$emit('add')
        }
      },
      created(){
        this.get()
      }
    };
    </script>
    

    2.11 @/views/user-manage/index.vue

    <template>
    <div>
      <div id="components-layout-demo-basic">
         <a-layout>
            <a-layout-header>
              <BreadCrumb style="float:left"></BreadCrumb>
    
            </a-layout-header>
            <a-layout>
                <a-layout-content>
                <div style="margin-bottom:80px">
                    <a-button type="danger" ghost style="float:left;margin-left:20px;margin-top:16px;color:pink;border-color:pink;font-size:16px" @click="addNew">
                    AddUser
                    </a-button>
                    <EditForm
                        :visible.sync="visible"
                        :userList='userList'
                        :roleList='roleList'
                        @add="add"
                    >
                    <!-- .sync控制组件是否显示 -->
                    </EditForm>
                    <Search 
                      style="margin-bottom:-20px;margin-top:10px" 
                      :searchList="searchList"
                      @find="find"
                      @getUser="getUser"
                    >
                    </Search>
                    
                </div>
                    <TableList
                      :userListGet="userListGet"
                      :userList="userList"
                      @getUser="getUser"
                      @add="add"
                    >
                    </TableList>
                    <Pagination
                      @getPage="getPage" 
                      :count="count" 
                      style="margin-top:20px; "             
                    ></Pagination>
                    <p></p>
                </a-layout-content>
            </a-layout>
         </a-layout>
      </div>
    </div>
    </template>
    
    <script>
    import BreadCrumb from "./components/BreadCrumb";
    import TableList from "./components/TableList";
    import Search from "./components/Search";
    import EditForm from "./components/EditForm";
    import Pagination from "./components/Pagination"
    
    import { add_user, search_for, get_userlist, update_user } from '@/http/apis';
    import { delete_user } from '../../http/apis';
    import { get_rolelist_new, add_role_user } from '../../http/apis';
    export default {
        components:{
            BreadCrumb,
            TableList,
            Search,
            EditForm,
            Pagination
        },
        data() {
            return {
                visible:false,
                userList: {
                  'id':'',
                  'username': '',
                  'passowrd': '',
                  'password_new': '',
                  'email':'',
                  'mobile':'',
                  'weixin':'',
                  'roles':[]
                  // 没定义roles字段的话,没办法绑定
                },
                roleList: [],
                userListGet:[],
                searchList:{
                    'username':'',
                    'page':1,
                    'page_size':4
    
                },
                updateUserList:[],
                // 当前页码
                current:1,
                // 总共的数据多少条
                count:0,
                addRoleList:[]
    
            }
        },
        methods: {
            addNew(){
              this.visible = true
              this.userList = {
                  'id':'',
                  'username': '',
                  'passowrd': '',
                  'password_new': '',
                  'email':'',
                  'mobile':'',
                  'weixin':'',
                  'roles':[]
                }
              // 用于控制组件显示
            },
            add(role_list){
              if(this.userList.id){            
                this.visible = true  
                update_user(this.userList).then(res=>{
                  // alert('修改成功')
                  this.getUser()
                })
    
              }else{
                
                // 添加用户,子组件中编辑的值实际上是写在父组件上面的
                add_user(this.userList).then(res=>{
                  
                  console.log(res)
                  alert('添加新用户成功')
                  this.getUser()
                  
              })   
                this.visible=false       
              }
            },
            find(){
              // 根据用户名查找用户信息
              search_for(this.searchList).then(res=>{
                // 阔落的办法可以解决bug,但是不支持查询出多条数据,因为没办法分页
                // if(this.searchList.username){
                //   // 修复如果没有搜索数据,回车就只能显示一个页面的bug
                //   console.log(res)
                //   this.userListGet = res.results
                //   this.count = res.results.length
                // }else{
                //   this.getUser()
                // }
                this.getUser()
    
              })
            },
            getUser(){
              this.searchList.page = this.current
              // 获取用户信息列表,父组件传递给子组件
              get_userlist(this.searchList).then(res=>{
                this.userListGet = res.results
                this.count = res.count
                console.log(this.count)
                console.log(this.userListGet)
    
              })
            },
            // 获取页码
            getPage(currentChild){
              // 获取到的currentChild是子组件传递过来是第几页
              this.current = currentChild
              console.log(this.current)
              this.getUser()
            },
            getRole(){
                get_rolelist_new().then(res=>{
                    this.roleList = res
                    console.log(111111)
                    console.log(this.roleList)
                })
            }
        },
        created() {
          this.getRole()
        }
    }
    </script>
    
    <style scoped>
    #components-layout-demo-basic {
      text-align: center;
    }
    #components-layout-demo-basic .ant-layout-header,
    #components-layout-demo-basic .ant-layout-footer {
      background: white;
      color: #fff;
    }
    #components-layout-demo-basic .ant-layout-footer {
      line-height: 1.5;
    }
    #components-layout-demo-basic .ant-layout-content {
      background: white;
      color: #fff;
      min-height: 120px;
      line-height: 120px;
    }
    #components-layout-demo-basic > .ant-layout {
      margin-bottom: 48px;
    }
    #components-layout-demo-basic > .ant-layout:last-child {
      margin: 0;
    }
    </style>
    

    2.12 @/router/index.js

    import Vue from 'vue'
    import Router from 'vue-router'
    
    import Home from '@/components/layout/Home'
    const page = name => () => import('@/views/' + name)
    Vue.use(Router)
    
    export default new Router({
      mode: 'history',
      routes: [
        { path: '/login',component: page('Login'),name: '登录'},
        // { path: '/aaa',component: page('approveconf-manage/index'),name: '测试approveconf'},
        { path: '/',component: Home,name: 'home',
          children: [
            { path: 'usermanage', component: page('user-manage/index'), name: '信息管理' },
            { path: 'rolemanage', component: page('role-manage/index'), name: '角色管理' },
            { path: 'flowtype', component: page('flowtype-manage/index'), name: '模板分类管理' },
            { path: 'flowconf', component: page('flowconf-manage/index'), name: '工单模板管理' },
            { path: 'approveconf', component: page('approveconf-manage/index'), name: '新建模板管理' },
            { path: 'workorder', component: page('workorder-manage/index'), name: '实例化工单' },
            { path: 'flowconfform', component: page('flowconfform-manage/index'), name: '实例化工单form' },
            { path: 'baidu', component: page('BaiDu'), name: '跳转百度' },      
          ]
        }
      ]
    })
    
    
  • 相关阅读:
    centos7.6 使用yum安装mysql5.7
    解决hadoop本地库问题
    docker-compose 启动警告
    docker 安装zabbix5.0 界面乱码问题解决
    docker 部署zabbix问题
    zookeeper 超时问题
    hbase regionserver异常宕机
    (转载)hadoop 滚动升级
    hadoop Requested data length 86483783 is longer than maximum configured RPC length
    zkfc 异常退出问题,报错Received stat error from Zookeeper. code:CONNECTIONLOSS
  • 原文地址:https://www.cnblogs.com/mapel1594184/p/14059813.html
Copyright © 2011-2022 走看看