• 平台支持mock功能—未完成版


    项目背景:

    目前测试接口有些是依赖第三方接口,若第三方接口出现异常,会对测试进度有所影响。需要开发mock相关功能辅助测试。

    技术选型:

    1.前端:python+xadmin+django+mysql,通过界面录入生成wiremock下mapping、_files文件夹下的json文件;

    2.后端:WireMock的standalone模式,通过shell脚本进行一键启停管理,以及实时刷新url、mapping映射。-----未完成

    wiremock工作原理:

    官网地址:http://wiremock.org/

    最新jar包下载地址:http://repo1.maven.org/maven2/com/github/tomakehurst/wiremock-standalone/2.9.0/wiremock-standalone-2.9.0.jar

    启动jar包:java -jar wiremock-standalone-2.9.0.jar –port 9999 —verbose

    (–port设定端口为9999; –verbose开启日志。更多参数需要参考:
    http://wiremock.org/docs/running-standalone/
    启动后在同目录下生成两个空的文件夹:__files和mappings。__files是放上传/下载/录制文件的,mappings放response和request url的映射的。
    在mappings文件夹下随便创建一个*.json文件,比如长下面这样:

    "request": {
            "method": "GET",
            "url": "/api/testdetail"
        },
        "response": {
            "status": 200,
            "bodyFileName": "testdetail.json”, 
            "headers": {
                "Content-Type": "application/json",
                "Cache-Control": "max-age=86400"
            }
        }
    }
    

    bodyFileName还可以是html、xml等文档。
    在浏览器或者使用curl命令,调用http://localhost:9999/api/testdetail,就能返回testdetail.json的内容了。testdetail.json就是需要我们在__files里面建立的响应文件。wiremock也支持直接在response结构体中返回响应内容,比如在mapping文件中,将response写成下面这样:

    "response": {
        "status": 200,
        "body": “Hello world ",
        "headers": {
            "Content-Type": "application/json",
            "Cache-Control": "max-age=86400"
        }
    

    当发送请求时候,将直接返回“Hello world”。

    前端实现:

    1.思路分析:

    1)添加:

    支持get和post两种,其中:get可带请求参数,也可不带;post请求必带请求参数;返回类型可为text,也可为json类型;添加后应根据选择请求方式和请求返回类型生成不同格式的json文件;

    2)删除:

    删除时应同时删除已生成的json文件;

    2.代码部分:

    views.py:

    from __future__ import unicode_literals
    from django.shortcuts import render,redirect,HttpResponse
    from mockserver import models
    from .mock_forms import *
    from django.db.models import  Q
    from utils.pagination import *
    from mockjson import *
    import json
    # Create your views here.
    class JsonCustomEncoder(json.JSONEncoder):
        def default(self, field):
            if isinstance(field, ValidationError):
                return {'code': field.code, 'messages': field.messages}
            else:
                return json.JSONEncoder.default(self, field)
    def MockManage(request,mid):
        '''mock接口管理'''
        if request.method == "GET":
            method_type = request.GET.get("method_type")
            keywords = request.GET.get("keywords")
            reset = request.GET.get("reset")
            if reset:
                return redirect('/mock/mockmanage-%s' % mid)
            else:
                project_info = models.MockProject.objects.filter(id=mid).values("mockname", 'id')
                if not method_type:
                    method_type = 0
                elif int(method_type) == 1:
                    selectstatus = "GET"
                elif int(method_type) == 2:
                    selectstatus = "POST"
                if not keywords:
                    keywords = ""
                if int(method_type) == 0:
                    selectstatus = u"全部"
                    counts = models.MockDetail.objects.filter(Q(mock_name__contains=keywords),De_Pro_id = mid).count()
                    if counts:
                        mockinfo = models.MockDetail.objects.filter(Q(mock_name__contains=keywords),De_Pro_id = mid).values(
                            'id',
                            "mock_name",
                            "mock_summary",
                            "mock_method",
                            "mock_url",
                            "mock_status",
                            "mock_query"
                        ).order_by("id")
                        current_page = request.GET.get('p', 1)
                        current_page = int(current_page)
                        page_obj = Page(current_page, counts)
                        try:
                            mockinfo = mockinfo[page_obj.start:page_obj.end]
                            now_url = request.get_full_path()
                            if "&p=" in now_url:
                                now_url = (now_url.split("&p="))[0]
                            elif "?p=" in now_url:
                                now_url = (now_url.split("?p="))[0]
                            page_str = page_obj.page_str(now_url)
                        except Exception:
                            mockinfo = 0
                            page_str = 0
                        return render(
                            request,
                            'mockcenter/mockmanage.html',{
                                'project_info':project_info,
                                'counts':counts,
                                "mockinfo":mockinfo,
                                'keywords': keywords,
                                'selectstatus': selectstatus,
                                "page_str": page_str,
                            }
                        )
                    else:
                        counts = 0
                        return render(
                            request,
                            'mockcenter/mockmanage.html', {
                                'project_info': project_info,
                                'counts': counts,
                                'keywords': keywords,
                                'selectstatus': selectstatus,
                            }
                        )
                elif int(method_type) == 1 or int(method_type) == 2:
                    counts = models.MockDetail.objects.filter(Q(mock_name__contains=keywords), De_Pro_id=mid,mock_method=selectstatus).count()
                    if counts:
                        mockinfo = models.MockDetail.objects.filter(Q(mock_name__contains=keywords), mock_method=selectstatus,De_Pro_id=mid).values(
                            'id',
                            "mock_name",
                            "mock_summary",
                            "mock_method",
                            "mock_url",
                            "mock_status",
                            "mock_query"
                        ).order_by("id")
                        current_page = request.GET.get('p', 1)
                        current_page = int(current_page)
                        page_obj = Page(current_page,counts)
                        try:
                            mockinfo = mockinfo[page_obj.start:page_obj.end]
                            now_url = request.get_full_path()
                            if "&p=" in now_url:
                                now_url = (now_url.split("&p="))[0]
                            elif "?p=" in now_url:
                                now_url = (now_url.split("?p="))[0]
                            page_str = page_obj.page_str(now_url)
                        except Exception:
                            mockinfo = 0
                            page_str = 0
                        return render(
                            request,
                            'mockcenter/mockmanage.html', {
                                'project_info': project_info,
                                'counts': counts,
                                "mockinfo": mockinfo,
                                'keywords': keywords,
                                'selectstatus': selectstatus,
                                "page_str": page_str,
                            }
                        )
                    else:
                        counts = 0
                        return render(
                            request,
                            'mockcenter/mockmanage.html', {
                                'project_info': project_info,
                                'counts': counts,
                                'keywords': keywords,
                                'selectstatus': selectstatus,
                            }
                        )
    def AddMock(request,mid):
        '''增加mock接口'''
        if request.method == "GET":
            project_info = models.MockProject.objects.filter(id=mid).values("mockname", 'id','mockdetail__mock_method')
            return render(
                request,
                'mockcenter/mockadd.html',{
                    'mid':mid,
                    'project_info': project_info,
                }
            )
        elif request.method == "POST":
            mockname = request.POST.get("mockname")
            mocksummary = request.POST.get("mocksummary")
            mock_method = request.POST.get("mock_method")
            mockurl = request.POST.get("mockurl")
            mockquery = request.POST.get("mockquery")
            mockstatus = request.POST.get("mockstatus")
            response_json = request.POST.get("response_json")
            response_text = request.POST.get("response_text")
            mockheaders = request.POST.get("mockheaders")
            mockseconds = request.POST.get("mockseconds")
            mock_stype = request.POST.get("mock_stype")
            ret={'status':False,'data':None,'error':None}
            obj = Mock_FM(request.POST)
            if obj.is_valid():
                if str(mock_stype) == "TEXT":
                    mockresponse = response_text
                    print(mockresponse)
                elif str(mock_stype) == "JSON":
                    mockresponse = response_json
                mock_info = {
                    "mockname":mockname,
                    "url":mockurl,
                    "method":mock_method,
                    "mockquery":mockquery,
                    "status":mockstatus,
                    "mock_type":mock_stype,
                    "response":mockresponse,
                    "headers":mockheaders,
                    "mockseconds":mockseconds
                }
                Make_mockjson(mock_info) #往wiremock的mappings和__files文件中新增json文件
                models.MockDetail.objects.create(
                    De_Pro_id=mid,
                    mock_name=mockname,
                    mock_method=mock_method,
                    mock_url=mockurl,
                    mock_summary=mocksummary,
                    mock_status=mockstatus,
                    mock_stype = mock_stype,
                    mock_reponse=mockresponse,
                    mock_query=mockquery,
                    reponse_headers=mockheaders,
                    mock_seconds=mockseconds
                )
                ret['status'] = True
            else:
                print(obj.errors.as_data())
                ret['status'] = False
                ret['error'] = obj.errors.as_data()
            result = json.dumps(ret,cls=JsonCustomEncoder)
            return HttpResponse(result)
    def DelMock(request,mid):
        '''删除mock接口'''
        row_id = request.POST.get("row_id")
        if row_id:
            row_id = row_id.split(",")
            if len(row_id) > 1:
                for i in row_id[1:]:
                    models.MockDetail.objects.filter(id=i,De_Pro_id=mid).delete()
            else:
                models.MockDetail.objects.filter(id=row_id[0], De_Pro_id=mid).delete()
        return redirect("/mock/mockmanage-%s"%mid)
    def EditMock(request,mid,cid):
        if request.method == "GET":
            project_info = models.MockProject.objects.filter(id=mid).values("mockname",'id')
            mockinfo = models.MockDetail.objects.filter(De_Pro_id=mid,id=cid).all()
            return render(
                request,
                "mockcenter/mockedit.html",{
                    "mid":mid,
                    "project_info":project_info,
                    "mockinfo":mockinfo
                })
        elif request.method == "POST":
            mockname = request.POST.get("mockname")
            mocksummary = request.POST.get("mocksummary")
            mock_method = request.POST.get("mock_method")
            mockurl = request.POST.get("mockurl")
            mockquery = request.POST.get("mockquery")
            mockstatus = request.POST.get("mockstatus")
            mockresponse = request.POST.get("mockresponse")
            mockheaders = request.POST.get("mockheaders")
            mockseconds = request.POST.get("mockseconds")
            ret = {'status': False, 'data': None, 'error': None}
            obj = Mock_FM(request.POST)
            if obj.is_valid():
                old_mockinfo = models.MockDetail.objects.filter(De_Pro_id=mid,mock_name=mockname).values("id")
                try:
                    if int(old_mockinfo[0]["id"]) != int(cid):
                        edict_dir = {}
                        edict_dir['mockname']= [ValidationError(u"已存在相同名称的接口,请重新输入!")]
                        ret['status'] = False
                        ret['error'] = edict_dir
                    else:
                        models.MockDetail.objects.filter(De_Pro_id=mid, id=cid).update(
                            mock_name=mockname,
                            mock_method=mock_method,
                            mock_url=mockurl,
                            mock_summary=mocksummary,
                            mock_status=mockstatus,
                            mock_reponse=mockresponse,
                            mock_query=mockquery,
                            reponse_headers=mockheaders,
                            mock_seconds=mockseconds
                        )
                        ret['status'] = True
                except Exception:
                    models.MockDetail.objects.filter(De_Pro_id=mid, id=cid).update(
                        mock_name=mockname,
                        mock_method=mock_method,
                        mock_url=mockurl,
                        mock_summary=mocksummary,
                        mock_status=mockstatus,
                        mock_reponse=mockresponse,
                        mock_query=mockquery,
                        reponse_headers=mockheaders,
                        mock_seconds=mockseconds
                    )
                    ret['status'] = True
            else:
                ret['status'] = False
                print(obj.errors.as_data())
                ret['error'] = obj.errors.as_data()
            result = json.dumps(ret, cls=JsonCustomEncoder)
            return HttpResponse(result)
    

    mock_forms.py:

    # -*- coding:utf-8 -*-
    # __author__ == 'cc'
    from django import forms
    from django.forms import fields
    from django.core.exceptions import ValidationError
    from mockserver import models
    import re,json
    class Mock_FM(forms.Form):
        mockname = fields.CharField(
            max_length=64,
            required=True,
            error_messages={
                'required':u'接口名称不能为空',
                'max_length':u"接口名称最多为64个字符",
            }
        )
        mocksummary = fields.CharField(
            max_length=512,
            required=True,
            error_messages={
                'required': u'接口描述不能为空',
                'max_length': u"接口描述最多为512个字符",
            }
        )
        mock_method = fields.CharField(
            required=True
        )
        mock_stype = fields.CharField(
            required=True
        )
        mockurl = fields.CharField(
            max_length=255,
            required=True,
            error_messages={
                'required': u'url不能为空',
                'max_length': u"url最多为255个字符",
            }
        )
        mockquery = forms.CharField(
            max_length=512,
            required=False,
            error_messages={
                'max_length': u"请求参数最多为512个字符",
            }
        )
        mockstatus = forms.IntegerField(error_messages={
            'required':u"状态码不能为空",
            "invalid":u"必须输入正确的状态码",
        })
        response_text = fields.CharField(
            max_length=6144,
            required=False,
            error_messages={
                'max_length': u"返回结果最多为6144个字符",
            }
        )
        response_json = fields.CharField(
            max_length=6144,
            required=False,
            error_messages={
                'max_length': u"返回结果最多为6144个字符",
            }
        )
        mockheaders = fields.CharField(
            max_length=2048,
            required=False,
            error_messages={
                'max_length': u"返回头最多为2048个字符",
            }
        )
        mockseconds = forms.CharField(
            max_length=255,
            required=False,
            error_messages={
                'max_length': u"延迟时间最多为255个字符",
            }
        )
        def clean_mock_name(self):
            mockname = self.cleaned_data['mock_name']
            if mockname:
                c = models.MockDetail.objects.filter(mock_name=mockname).count()
                if c:
                    raise ValidationError(u"接口描述已存在,请重新输入!")
                else:
                    return mockname
     
        def clean_mock_url(self):
            mock_url = self.cleaned_data['mock_url']
            if mock_url:
                c = models.MockDetail.objects.filter(mock_url=mock_url).count()
                if c:
                    raise ValidationError(u"接口描述已存在,请重新输入!")
                else:
                    return mock_url
        def clean_mockquery(self):
            mockquery = self.cleaned_data['mockquery']
            mock_method = self.cleaned_data['mock_method']
            if mock_method == "GET":
                if mockquery:
                    mockquery = str(mockquery).replace("'", '"')
                    try:
                        mockquery = json.loads(mockquery)
                        if isinstance(mockquery, dict):
                            return mockquery
                        else:
                            raise ValidationError(u"请输入正确格式的请求参数!")
                    except ValueError:
                        raise ValidationError(u"请输入正确格式的请求参数!")
                else:
                    mockquery = ""
                    return mockquery
            elif mock_method == "POST":
                if mockquery:
                    mockquery = str(mockquery).replace("'", '"')
                    try:
                        mockquery = json.loads(mockquery)
                        if isinstance(mockquery, dict):
                            return mockquery
                        else:
                            raise ValidationError(u"请输入正确格式的请求参数!")
                    except ValueError:
                        raise ValidationError(u"请输入正确格式的请求参数!")
                else:
                    raise ValidationError(u"请输入正确格式的请求参数!")
        def clean_mockresponse(self):
            mock_stype = self.cleaned_data['mock_stype']
            if str(mock_stype) == "TEXT":
                mockresponse = self.cleaned_data['response_text']
                if mockresponse:
                    mockresponse = str(mockresponse).replace("'", '"')
                    return mockresponse
                else:
                    raise ValidationError(u"返回结果不能为空!")
            elif str(mock_stype) == "JSON":
                mockresponse = self.cleaned_data['response_json']
                if mockresponse:
                    mockresponse = str(mockresponse).replace("'", '"')
                    try:
                        mockresponse = json.loads(mockresponse)
                        if isinstance(mockresponse, dict):
                            return mockresponse
                        else:
                            raise ValidationError(u"请输入正确格式的返回结果!")
                    except ValueError:
                        raise ValidationError(u"请输入正确格式的返回结果!")
                else:
                    raise ValidationError(u"返回结果不能为空!")
        def clean_mockheaders(self):
            mockheaders = self.cleaned_data['mockheaders']
            mock_stype = self.cleaned_data['mock_stype']
            mockheaders = str(mockheaders).replace("'", '"')
            if str(mock_stype) == "TEXT":
                return mockheaders
            elif str(mock_stype) == "JSON":
                try:
                    mockheaders = json.loads(mockheaders)
                    if isinstance(mockheaders,dict):
                        return mockheaders
                    else:
                        raise ValidationError(u"请输入正确格式的返回头!")
                except ValueError:
                    raise ValidationError(u"请输入正确格式的返回结果头!")
        def clean_mockseconds(self):
            mockseconds = self.cleaned_data['mockseconds']
            if mockseconds:
                return mockseconds
            else:
                mockseconds = ""
                return mockseconds
    

    生成json文件:

    # -*- coding:utf-8 -*-
    # __author__ == 'cc'
    import json,os
    def Make_mockjson(mockinfo):
        '''获取mock信息,创建符合wiremock要求的json文件'''
        json_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
        mapping_name = "%s_%s%s.json" % (mockinfo['url'].split("/")[-1],mockinfo['method'],mockinfo['status']) #mapping夹下的json文件名:截取url最后路径_接口方式_状态码
        file_name = "file_%s%s.json"%(mockinfo['url'].split("/")[-1],mockinfo['status'])#__file文件夹下的json文件名:file_截取url最后路径_状态码
        if mockinfo['method'] == "GET":
            if mockinfo['mockquery']:
                mockquery = json.loads(mockinfo['mockquery'])
                query_infos = ""
                for k,v in enumerate(mockquery):
                    query_infos +="%s=%s&"%(v,mockquery[v]) #参数组合成k1=v1&k2=v2格式
                if str(mockinfo['mock_type']) == "JSON": #接口方式为get、有请求参数且返回类型为json时,创建如下格式的json文件
                    json_data = {
                        "request":{
                            "method":"GET",
                            "urlPattern":r"%s?%s"%(mockinfo['url'],query_infos[:-1]),
                        },
                        "response":{
                            "status":mockinfo['status'],
                            "bodyFileName":"%s.json"%file_name,
                            "headers":json.loads(mockinfo['headers'])
                        }
                    }
                elif str(mockinfo['mock_type']) == "TEXT":#接口方式为get、有请求参数且返回类型为text时,创建如下格式的json文件
                    json_data = {
                        "request": {
                            "method": "GET",
                            "urlPattern": r"%s?%s" % (mockinfo['url'], query_infos[:-1]),
                        },
                        "response": {
                            "status": mockinfo['status'],
                            "body": mockinfo['response'],
                            "headers": json.loads(mockinfo['headers'])
                        }
                    }
            else:
                if str(mockinfo['mock_type']) == "JSON": #接口方式为get,m
                    json_data = {
                        "request":{
                            "method":"GET",
                            "url":mockinfo['url']
                        },
                        "response":{
                            "status":mockinfo['status'],
                            "bodyFileName": "%s.json" % file_name,
                            "headers": json.loads(mockinfo['headers'])
                        }
                    }
     
                elif str(mockinfo['mock_type']) == "TEXT":
                    json_data = {
                        "request": {
                            "method": "GET",
                            "url": mockinfo['url']
                        },
                        "response": {
                            "status": mockinfo['status'],
                            "body": mockinfo['response'],
                        }
                    }
        elif mockinfo['method'] == "POST":
            mockquery = json.loads(mockinfo['mockquery'])
            json_query = json.dumps(mockquery)
            json_query_new=json_query.replace('"',r'"')
            if str(mockinfo['mock_type']) == "JSON":
                json_data = {
                    "request": {
                        "method": "POST",
                        "url": mockinfo['url'],
                        "bodyPatterns":[
                            {
                                "equalToJson":"%s"%json_query_new,
                                "jsonCompareMode":"LENIENT"
                            }
                        ]
                    },
                    "response": {
                        "status": mockinfo['status'],
                        "bodyFileName": "%s" % file_name,
                        "headers": json.loads(mockinfo['headers'])
                    }
                }
            elif str(mockinfo['mock_type']) == "TEXT":
                json_data = {
                    "request": {
                        "method": "POST",
                        "url": mockinfo['url'],
                        "bodyPatterns": [
                            {
                                "equalToJson": "%s" % json_query_new,
                                "jsonCompareMode": "LENIENT"
                            }
                        ]
                    },
                    "response": {
                        "status": mockinfo['status'],
                        "body": mockinfo['response'],
                    }
                }
        mapping_data = json.dumps(json_data)
        mapping_path = os.path.join(json_dir,'wiremock/mappings/%s'%mapping_name)
        with open(mapping_path,'wb+') as f:
            f.write(mapping_data)
        if str(mockinfo['mock_type']) == "JSON":
            file_path =os.path.join(json_dir,'wiremock\__files\%s'%file_name)
            post_response = json.dumps(str(mockinfo['response']))
            with open(file_path,'wb+') as f1:
                f1.write(json.loads(post_response))
    def Del_mockjson():
        '''删除json文件'''
        pass
    

    html模板:

    1)mockmanage.html

    <div class="navbar content-navbar navbar-default navbar-xs" data-toggle="breakpoint" data-class-xs="navbar content-navbar navbar-inverse navbar-xs" data-class-sm="navbar content-navbar navbar-default navbar-xs">
            <div class="navbar-header">
                <button class="navbar-toggle pull-left" data-toggle="class" data-target="#body-content" data-class-name="show_menu">
                  <i class="fa fa-list"></i>
                </button>
                <a class="navbar-toggle pull-right"><i class="fa fa-plus"></i></a>
                <button class="navbar-toggle pull-right" data-toggle="collapse" data-target=".content-navbar .navbar-collapse">
                  <i class="fa fa-filter"></i>
                </button>
                  <a class="navbar-brand" data-toggle="collapse" data-target="#top-nav .navbar-collapse">
                    <i class="fa fa-eercast"></i>[{{ project_info.0.mockname }}] MOCK信息
                  </a>
            </div>
            <div class="navbar-collapse collapse">
                {% if user.is_superuser %}
                    <div class="navbar-btn pull-left hide-xs" id="Del_chos">
                        {% csrf_token %}
                        <a class="btn btn_del"><i class="fa fa-minus"></i>
                        批量删除
                        </a>
                    </div>
                {% endif %}
                <div class="mockadd_reset">
                    <div class="navbar-btn pull-right hide-xs">
                        <a href="../mockmanage-{{ project_info.0.id }}/add" class="btn btn-primary"><i class="fa fa-plus"></i>
                        增加 Mock接口
                        </a>
                    </div>
                </div>
            </div>
        </div>
        <div class="classdiv">
            <div class="selecth4">
                <span>接口查询</span>
            </div>
            <form id="search_mock" method="get" style="display: inline-block">
                <div class="selecttitle">
                    <span>
                        <i class="fa fa-hand-o-right selectsize">接口名称:</i>
                        <input type="text" class="input-title" placeholder="请输入要查询的接口名称" name="keywords" value="{{ keywords }}"/>
                    </span>
                </div>
                <div class="selectstatus">
                    <span>
                        <i class="fa fa-hand-o-right selectsize">接口类型:</i>
                        <select class="status-select" name="method_type">
                            {% if selectstatus == "GET" %}
                                <option value="0">全部</option>
                                <option value="1" selected="selected">GET</option>
                                <option value="2">POST</option>
                            {% elif selectstatus == "POST" %}
                                <option value="0">全部</option>
                                <option value="1">GET</option>
                                <option value="2" selected="selected">POST</option>
                            {% else %}
                                <option value="0" selected="selected">全部</option>
                                <option value="1">GET</option>
                                <option value="2">POST</option>
                            {% endif %}
                        </select>
                    </span>
                </div>
                <button class="btn btn-primary selectbtn" type="submit">查询接口</button>
                <input class="selreset btn btn-primary" type="submit" name="reset" value="重置查询"/>
            </form>
        </div>
        <ul class="pagination pagination-sm pagination-left pagination-inline">
          <li><span><span class="text-success">{{ counts }}</span> 接口信息</span></li>
        </ul>
        <div class="results table-responsive">
            {% if counts %}
            <table class="table table-bordered table-striped table-hover">
                <thead>
                    <tr>
                        <th scope="col" class="action-checkbox-column">
                            <input type="checkbox" class="action-all"/>
                        </th>
                        <th scope="col" class="th_title">
                            接口名称
                        </th>
                        <th scope="col" class="th_title">
                            接口描述
                        </th>
                        <th scope="col" class="th_title">
                            接口类型
                        </th>
                        <th scope="col" class="th_title">
                            URL
                        </th>
                        <th scope="col" class="th_title">
                            状态码
                        </th>
                        <th scope="col" class="th_title">
                            操作
                        </th>
                    </tr>
                </thead>
                <tbody>
                    {% for m in mockinfo %}
                        <tr class="grid-item">
                            <td class="relatd">
                                <input type="checkbox" value="{{ m.id }}" name="ck" class="c_checkbox"/>
                            </td>
                            <td class="relatd mname">
                                <span>{{ m.mock_name }}</span>
                            </td>
                            <td class="relatd mname">
                                <span>{{ m.mock_summary }}</span>
                            </td>
                            <td class="relatd cstatus">
                                <span>{{ m.mock_method }}</span>
                            </td>
                            <td class="relatd urlcs">
                                <span>{{ m.mock_url }}</span>
                            </td>
                            <td class="relatd cstatus">
                                <span>{{ m.mock_status }}</span>
                            </td>
                            <td class="relatd">
                                <div style="position: absolute;top:2%">
                                    <a class="fa fa-align-center case_action_edit" href="edit-{{ m.id }}">
                                        <span>编辑</span>
                                    </a>
                                    {% if user.is_superuser %}
                                    <a class="fa fa-minus-square case_action_del" row_id = {{ m.id }}>
                                        <span> 删除</span>
                                    </a>
                                    {% endif %}
                                </div>
                            </td>
                        </tr>
                    {% endfor %}
                </tbody>
            </table>
            {% else %}
            <div style="text-align: center">
                <span>暂无Mock接口信息</span>
            </div>
            {% endif %}
            <div class="v-transfer-dom hide" id="Del_dom">
                <div class="ivu-modal-mask"></div>
                <div class="ivu-modal-wrap">
                    <div class="ivu-modal" style=" 416px;">
                        <div class="ivu-modal-content">
                            <div class="ivu-modal-body">
                                <div class="ivu-modal-confirm">
                                    <div class="ivu-modal-confirm-head">
                                        <div class="ivu-modal-confirm-head-title">提示</div>
                                    </div>
                                    <div class="ivu-modal-confirm-body">
                                        <div class="ivu-modal-confirm-body-icon ivu-modal-confirm-body-icon-confirm">
                                            <i class="fa fa-question"></i>
                                        </div>
                                        <div>该操作无法撤消,是否继续删除?</div>
                                    </div>
                                    <form class="ivu-modal-confirm-footer" method="post" action="delmock">
                                        {% csrf_token %}
                                        <input type="hidden" id="row_id" name="row_id"/>
                                        <button type="button" class="ivu-btn ivu-btn-text ivu-btn-large" id="del_console">
                                            <span>取消</span>
                                        </button>
                                        <button type="submit" class="ivu-btn ivu-btn-primary ivu-btn-large">
                                            <span>确定</span>
                                        </button>
                                    </form>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <div class="clearfix pagesty">
                <div class="pagination right" style="margin-top: 0">
                    {{ page_str }}
                </div>
            </div>
            <a href="#" class="fixedtool">顶部</a>
        </div>
    

    2)mockadd.html

    <div class="navbar content-navbar navbar-default navbar-xs" data-toggle="breakpoint" data-class-xs="navbar content-navbar navbar-inverse navbar-xs" data-class-sm="navbar content-navbar navbar-default navbar-xs">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle pull-left" onclick="javascript: history.back();"><i class="fa fa-arrow-left"></i></button>
                <a class="navbar-brand" data-toggle="collapse" data-target="#top-nav .navbar-collapse">
                <i class="fa fa-eercast"><sub class="fa fa-plus"></sub></i>
                增加 [{{ project_info.0.mockname }}]接口信息
                </a>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                </ul>
                <div class="navbar-btn pull-right hide-xs">
                </div>
            </div>
        </div>
        <form class="exform rended" enctype="multipart/form-data"  method="post" id="mockadd_form">
            <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}"/>
            <input type="hidden"  id="mockproject_id" value="{{ mid }}"/>
            <div class="form-body">
                <div id="div_mockname" class="casegroup">
                    <label class="group-label">
                        接口名称
                        <span style="color:red">*</span>
                    </label>
                    <div class="control_text">
                        <input class="case_input" type="text" name="mockname" id="text" placeholder="请输入接口名称"/>
                        <span id="mockname_error" class="error_cs"></span>
                    </div>
                </div>
                <div id="div_mocksummary" class="casegroup">
                    <label class="group-label">
                        接口描述
                        <span style="color:red">*</span>
                    </label>
                    <div class="control_text">
                        <input class="case_input" type="text" name="mocksummary" id="text" placeholder="请输入接口描述"/>
                        <span id="summary_error" class="error_cs"></span>
                    </div>
                </div>
                <div id="div_mock_method" class="casegroup">
                    <label class="group-label">
                        方法类型
                        <span style="color:red">*</span>
                    </label>
                    <div class="control_text">
                        <select class="status-select" name="mock_method">
                            <option value="GET">GET</option>
                            <option value="POST">POST</option>
                        </select>
                    </div>
                </div>
                <div id="div_mockurl" class="casegroup">
                    <label class="group-label">
                        URL
                        <span style="color:red">*</span>
                    </label>
                    <div class="control_text">
                        <input class="case_input" type="text" name="mockurl" id="id_mockurl" placeholder="请输入URL,格式:/%s/%s"/>
                        <span id="url_error" class="error_cs"></span>
                    </div>
                </div>
                 <div id="div_casestep" class="case_textarea">
                    <label class="group-label">
                        请求参数
                    </label>
                    <div class="control_text">
                        <textarea class="case_input textarea_nor" type="text" name="mockquery" placeholder='请输入json类型参数,如{"key1":"val1","key2":"val2"}' id="id_casestep"></textarea>
                        <span id="query_error" class="error_cs"></span>
                    </div>
                </div>
                <div id="div_mockstatus" class="casegroup">
                    <label class="group-label">
                        返回状态码
                        <span style="color:red">*</span>
                    </label>
                    <div class="control_text">
                        <input class="case_input" type="text" name="mockstatus" id="text" placeholder="请输入返回状态码"/>
                        <span id="status_error" class="error_cs"></span>
                    </div>
                </div>
                <div id="div_mock_rtype" class="casegroup">
                    <label class="group-label">
                        返回类型
                        <span style="color:red">*</span>
                    </label>
                    <div class="control_text">
                        <select class="status-select" name="mock_stype" id="mock_stype" onchange="ValChange()">
                            <option value="TEXT">TEXT</option>
                            <option value="JSON">JSON</option>
                        </select>
                    </div>
                </div>
                <div id="return_json" class="hide">
                    <div class="case_textarea">
                        <label class="group-label">
                            返回结果
                            <span style="color:red">*</span>
                        </label>
                        <div class="control_text">
                            <textarea class="case_input textarea_nor" type="text" placeholder='请输入json类型返回结果,如{"key1":"val1","key2":"val2"}' name="response_json"></textarea>
                            <span id="resopnse_error" class="error_cs"></span>
                        </div>
                    </div>
                    <div id="div_headers" class="case_textarea">
                        <label class="group-label">
                            返回头
                            <span style="color:red">*</span>
                        </label>
                        <div class="control_text">
                            <textarea class="case_input textarea_nor" type="text" placeholder='请输入json类型返回头,如{"key1":"val1","key2":"val2"}' name="mockheaders" id="id_mockheaders"></textarea>
                            <span id="headers_error" class="error_cs"></span>
                        </div>
                    </div>
                </div>
                <div class="case_textarea" id="return_text">
                    <label class="group-label">
                        返回结果
                        <span style="color:red">*</span>
                    </label>
                    <div class="control_text">
                        <textarea class="case_input textarea_nor" type="text" placeholder='请输入text类型返回结果' name="response_text"></textarea>
                        <span id="resopnse_error" class="error_cs"></span>
                    </div>
                </div>
                <div id="div_mockseconds" class="casegroup">
                    <label class="group-label">
                        响应延迟
                    </label>
                    <div class="control_text">
                        <input class="case_input" type="text" name="mockseconds" id="text" placeholder="请输入响应延迟时间,单位:毫秒"/>
                        <span id="seconds_error" class="error_cs"></span>
                    </div>
                </div>
            </div>
            <div class="form-actions well well-sm clearfix">
                <a id="addmocknow" class="default btn btn-primary hide-xs">
                    <i class="fa fa-save"></i>
                    保存
                </a>
                <div class="nav-collapse collapse more-btns">
                    <a id="mockanother" class="btn btn-default">保存并增加另一个</a>
                </div>
            </div>
        </form>
    

    3)mockedit.html

    <div class="navbar content-navbar navbar-default navbar-xs" data-toggle="breakpoint" data-class-xs="navbar content-navbar navbar-inverse navbar-xs" data-class-sm="navbar content-navbar navbar-default navbar-xs">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle pull-left" onclick="javascript: history.back();"><i class="fa fa-arrow-left"></i></button>
                <a class="navbar-brand" data-toggle="collapse" data-target="#top-nav .navbar-collapse">
                <i class="fa fa-eercast"><sub class="fa fa-plus"></sub></i>
                编辑 [{{ project_info.0.mockname }}]接口信息
                </a>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                </ul>
                <div class="navbar-btn pull-right hide-xs">
                </div>
            </div>
        </div>
        <form class="exform rended" enctype="multipart/form-data"  method="post" id="mockedit_form">
            <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}"/>
            <input type="hidden"  id="mockproject_id" value="{{ mid }}"/>
            {% for m in mockinfo %}
            <input type="hidden"  id="edit_id" value="{{ m.id }}"/>
            <div class="form-body">
                <div id="div_mockname" class="casegroup">
                    <label class="group-label">
                        接口名称
                        <span style="color:red">*</span>
                    </label>
                    <div class="control_text">
                        <input class="case_input" type="text" name="mockname" id="text" value="{{ m.mock_name }}"/>
                        <span id="mockname_error" class="error_cs"></span>
                    </div>
                </div>
                <div id="div_mocksummary" class="casegroup">
                    <label class="group-label">
                        接口描述
                        <span style="color:red">*</span>
                    </label>
                    <div class="control_text">
                        <input class="case_input" type="text" name="mocksummary" id="text" value="{{ m.mock_summary }}"/>
                        <span id="summary_error" class="error_cs"></span>
                    </div>
                </div>
                <div id="div_mock_method" class="casegroup">
                    <label class="group-label">
                        方法类型
                        <span style="color:red">*</span>
                    </label>
                    <div class="control_text">
                        <select class="status-select" name="mock_method">
                            {% if m.mock_method == "GET" %}
                                <option value="GET" selected="selected">GET</option>
                                <option value="POST">POST</option>
                            {% elif m.mock_method == "POST" %}
                                <option value="GET">GET</option>
                                <option value="POST" selected="selected">POST</option>
                            {% endif %}
                        </select>
                    </div>
                </div>
                <div id="div_mockurl" class="casegroup">
                    <label class="group-label">
                        URL
                        <span style="color:red">*</span>
                    </label>
                    <div class="control_text">
                        <input class="case_input" type="text" name="mockurl" id="id_mockurl" value="{{ m.mock_url }}"/>
                        <span id="url_error" class="error_cs"></span>
                    </div>
                </div>
                 <div id="div_casestep" class="case_textarea">
                    <label class="group-label">
                        请求参数
                    </label>
                    <div class="control_text">
                        <textarea class="case_input textarea_nor" type="text" name="mockquery" id="id_casestep">{{ m.mock_query }}</textarea>
                        <span id="query_error" class="error_cs"></span>
                    </div>
                </div>
                <div id="div_mockstatus" class="casegroup">
                    <label class="group-label">
                        返回状态码
                        <span style="color:red">*</span>
                    </label>
                    <div class="control_text">
                        <input class="case_input" type="text" name="mockstatus" id="text" value="{{ m.mock_status }}"/>
                        <span id="status_error" class="error_cs"></span>
                    </div>
                </div>
                <div id="div_response" class="case_textarea">
                    <label class="group-label">
                        返回结果
                        <span style="color:red">*</span>
                    </label>
                    <div class="control_text">
                        <textarea class="case_input textarea_nor" type="text" name="mockresponse" id="id_mockresponse">{{ m.mock_reponse }}</textarea>
                        <span id="resopnse_error" class="error_cs"></span>
                    </div>
                </div>
                <div id="div_headers" class="case_textarea">
                    <label class="group-label">
                        返回头
                        <span style="color:red">*</span>
                    </label>
                    <div class="control_text">
                        <textarea class="case_input textarea_nor" type="text"  name="mockheaders" id="id_mockheaders">{{ m.reponse_headers }}</textarea>
                        <span id="headers_error" class="error_cs"></span>
                    </div>
                </div>
                <div id="div_mockseconds" class="casegroup">
                    <label class="group-label">
                        响应延迟
                    </label>
                    <div class="control_text">
                        <input class="case_input" type="text" name="mockseconds" id="text" placeholder="请输入响应延迟时间,单位:毫秒" value="{{ m.mock_seconds }}"/>
                        <span id="seconds_error" class="error_cs"></span>
                    </div>
                </div>
            </div>
            {% endfor %}
            <div class="form-actions well well-sm clearfix">
                <a id="editmocknow" class="default btn btn-primary hide-xs">
                    <i class="fa fa-save"></i>
                    保存
                </a>
                <div class="nav-collapse collapse more-btns">
                    <a id="console_Editmock" class="btn btn-default" href="./">取消</a>
                </div>
            </div>
        </form>
    

    4)mock.js

    function ValChange() {
        var val = $("#mock_rtype").val();
        if(val == "TEXT"){
            $("#return_json").addClass("hide");
            $("#return_text").removeClass("hide");
        }else{
            $("#return_json").removeClass("hide");
            $("#return_text").addClass("hide");
        }
    };
    $.ajaxSetup({
            beforeSend:function (xhr,settings){
                xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken'));
            }
        });
        $("#addmocknow").click(function () {
            var mid=$("#mockproject_id").val();
           $.ajax({
                url: "/mock/mockmanage-%s/add"%mid,
                type: "POST",
                data:$('#mockadd_form').serialize(),
                success: function (data) {
                    var obj = JSON.parse(data);
                    if (obj.status) {
                        location.href="./";//若点击保存按钮,保存后返回到上级页面
                    }else{
                        if (obj.error.mockname){
                            $('#mockname_error').text(obj.error.mockname[0].messages);
                        }else{
                            if(obj.error.mocksummary){
                                $("#summary_error").text(obj.error.mocksummary[0].messages)
                            }else {
                                if (obj.error.mockurl) {
                                    $("#url_error").text(obj.error.mockurl[0].messages)
                                } else {
                                    if (obj.error.mockquery){
                                        $("#query_error").text(obj.error.mockquery[0].messages)
                                    }else{
                                        if (obj.error.mockstatus) {
                                            $("#status_error").text(obj.error.mockstatus[0].messages)
                                        }else {
                                            if (obj.error.mockresponse) {
                                                $("#resopnse_error").text(obj.error.mockresponse[0].messages)
                                            } else {
                                                if (obj.error.mockheaders) {
                                                    $("#headers_error").text(obj.error.mockheaders[0].messages)
                                                }else{
                                                    $("#headers_error").text(obj.error)
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }) 
        });
        $("#addanother").click(function () {
            var mid=$("#modeltype").val();
           $.ajax({
                url: "/case/casemanage-%s/add"%mid,
                type: "POST",
                data:$('#caseadd_form').serialize(),
                success: function (data) {
                    var obj = JSON.parse(data);
                    if (obj.status) {
                        location.reload();//若点击保存并增加另一个则刷新当前页面
                    }else{
                        $('#error_msg').text(obj.error);
                    }
                }
            }) 
        });
        $(".case_action_del").each(function () {
            $(this).click(function () {
                $(this).parents().find(".del_text").removeClass("hide");
                var row_id = $(this).attr("row_id");
                $("#row_id").val(row_id);
            })
        });
        $("#Del_chos").click(function () {
            $("#Del_dom").removeClass("hide");
        })
        $("#del_console").click(function () {
            $("#Del_dom").addClass("hide");
        });
        $("#editmocknow").click(function () {
            var mid=$("#mockproject_id").val();
            var cid = $("#edit_id").val();
           $.ajax({
                url: "/mock/mockmanage-%s/edit-%s"%(mid,cid),
                type: "POST",
                data:$('#mockedit_form').serialize(),
                success: function (data) {
                    var obj = JSON.parse(data);
                    if (obj.status) {
                        location.href="./";//若点击保存按钮,保存后返回到上级页面
                    }else{
                        if (obj.error.mockname){
                            $('#mockname_error').text(obj.error.mockname[0].messages);
                        }else{
                            if(obj.error.mocksummary){
                                $("#summary_error").text(obj.error.mocksummary[0].messages)
                            }else {
                                if (obj.error.mockurl) {
                                    $("#url_error").text(obj.error.mockurl[0].messages)
                                } else {
                                    if (obj.error.mockquery){
                                        $("#query_error").text(obj.error.mockquery[0].messages)
                                    }else{
                                        if (obj.error.mockstatus) {
                                            $("#status_error").text(obj.error.mockstatus[0].messages)
                                        }else {
                                            if (obj.error.mockresponse) {
                                                $("#resopnse_error").text(obj.error.mockresponse[0].messages)
                                            } else {
                                                if (obj.error.mockheaders) {
                                                    $("#headers_error").text(obj.error.mockheaders[0].messages)
                                                }else{
                                                    $("#headers_error").text(obj.error)
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            })
        });
    

    后端部分

    未实现---待补

    最终效果:

  • 相关阅读:
    如何为Android写一个PhoneGap插件
    Javascript高性能动画与页面渲染
    jquery mobile Popup
    android学习资料免费下载
    锋利的jquery第2版高清 pdf
    android获取sd卡最后一张照片
    mongodb 基础
    django 实现读写分离
    docker 部署django方式
    mysql 主从读写
  • 原文地址:https://www.cnblogs.com/cocc/p/12365701.html
Copyright © 2020-2023  润新知