Django+vue自动化测试平台(3)--发送接口请求/接口调试

体验地址:

http://1.12.224.200/
账号:test
密码:test

后端数据库+接口实现

目录与接口绑定数据库呈现:
在这里插入图片描述

接口信息模型:

# 接口信息
class Testcase(models.Model):
    t_name = models.CharField("用例名称", null=True, max_length=50)
    t_method = models.IntegerField("请求方法", null=True)  # 1:get, 2:post, 3:put, 4:delete
    t_url = models.TextField("url请求地址", null=True)
    t_params = models.CharField("请求参数", null=True, default=[], max_length=255)
    t_type = models.IntegerField("参数类型", null=True, default=2)  # 1:form-data, 2:Json, 3:x-www-form-urlencoded, 4:None
    api_type = models.IntegerField("接口类型", null=True, default=1)  # 1:普通接口,可做定制化接口 
    t_header = models.TextField("请求头", null=True, default={})
    t_body = models.TextField("请求体", null=True, default={})
    t_extract = models.CharField("参数提取", null=True, default=[], max_length=255)
    update_time = models.DateTimeField("更新时间", auto_now=True)
    create_time = models.DateTimeField("创建时间", auto_now_add=True)
    t_environment = models.ForeignKey(Environment, on_delete=models.CASCADE, default=1)
    t_user = models.ForeignKey(Userinfo, on_delete=models.CASCADE)

    def __str__(self):
        return self.t_name


# 本地变量
class Variable_local(models.Model):
    local_name = models.CharField("变量名称", null=False, max_length=255)
    local_data = models.CharField("变量路径", null=True, max_length=255)
    local_result = models.CharField("变量结果", null=False, max_length=255)
    local_description = models.CharField("变量描述", null=True, max_length=255)
    update_time = models.DateTimeField("更新时间", auto_now=True)
    create_time = models.DateTimeField("创建时间", auto_now_add=True)
    local_user = models.ForeignKey(Userinfo, on_delete=models.CASCADE)

    def __str__(self):
        return self.local_name


# 断言
class Asserts(models.Model):
    assert_key = models.CharField("断言字段名", null=False, max_length=255)
    assert_value = models.TextField("断言结果", null=False)
    assert_status = models.CharField("断言状态", null=True, max_length=255)
    assert_testcase = models.ForeignKey(Testcase, on_delete=models.CASCADE)

    def __str__(self):
        return self.assert_key

获取接口信息接口实现:

class Singlecase(View):
    # 获取单个测试用例
    def post(self, request, *args, **kwargs):
        data = json.loads(request.body)
        case_id = data["menu_id"]  # 通过目录id帮绑定接口id
        menu = Menu.objects.get(id=case_id)
        c_id = menu.testcase_id
        asserts = Asserts.objects.filter(assert_testcase_id=c_id)
        assert_list = []
        for a in asserts:
            assert_dict = {
                "assert_key": a.assert_key,
                "assert_value": a.assert_value
            }
            assert_list.append(assert_dict)
        case = Testcase.objects.get(id=c_id)
        case_dict = {
            "id": menu.testcase_id,
            "name": case.t_name,
            "method": case.t_method,
            "api_type": case.api_type,
            "url": case.t_url,
            "body_type": case.t_type,
            "params": json.loads(case.t_params.replace("\'", "\"")),
            "headers": case.t_header,
            "extract": json.loads(case.t_extract.replace("\'", "\"")),
            "body": json.loads(case.t_body.replace("\'", "\"")),
            "environment_id": case.t_environment_id,
            "assert_form": assert_list
        }
        return JsonResponse(case_dict)

环境模型:

class Environment(models.Model):
    """
    API环境设置
    """
    e_name = models.CharField("API环境名称", max_length=200, null=False)
    e_address = models.CharField("API环境标题名称", max_length=200, null=False)
    e_describe = models.TextField("API环境描述", default="", null=True)
    create_time = models.DateTimeField("创建时间", auto_now_add=True)
    update_time = models.DateTimeField("更新时间", auto_now_add=True)
    e_user = models.ForeignKey(Userinfo, on_delete=models.CASCADE)

    def __str__(self):
        return self.e_name

获取环境接口:

class Env_list(View):

    def post(self, request, *args, **kwargs):
        envs = Environment.objects.all()
        env_list = []
        for env in envs:
            env_dict = {
                "environment_id": env.id,
                "environment_name": env.e_name
            }
            env_list.append(env_dict)
        return JsonResponse({
            "code": 200,
            "message": "获取环境列表成功",
            "content": env_list
        })

前面处理好了接下来就是url的配置啦:
在这里插入图片描述

# 在app文件夹下面新建urls文件夹
# urls文件下面根据不同模块新建底部文件
# 新增xxx_urls.py文件,格式跟下方保持一致即可,不做详细说明,举个例子而已
urlpatterns = [
    path("api/enviroment/all", Env_view.as_view()),  # 环境列表

    path("api/enviroment/list", Env_list.as_view()),  # 接口信息中的环境列表

    path("api/enviroment/get_environment", get_environment),  # 获取单个环境信息

    path("api/enviroment/add_env", add_environment),  # 新增环境

    path("api/enviroment/edit_env", edit_environment),  # 编辑环境
]

发送接口请求:

import json
import logging
import re
import urllib
from datetime import datetime
import hashlib
from urllib.parse import urlencode

import requests
from django.http import JsonResponse
from django.views import View
from lapi_app.models.environment_model.environment import Environment
from lapi_app.models.testcase_model.testcase import Variable_local, Testcase, Asserts

logger = logging.getLogger('django')


class Send_request(View):

    def post(self, request, *args, **kwargs):
        body_data = request.body
        if not body_data:
            return JsonResponse({
                "code": 100,
                "message": "参数异常"
            })
        data = json.loads(body_data)
        t_id = data["testcase_id"]
        t_url = data["url"]
        t_type = data["body_type"]
        t_body = data["body"]
        t_method = data["method"]
        t_params = data["params"]
        t_headers = data["headers"]
        t_assert = data["assert"]
        api_type = data["api_type"]
        t_env_id = data["environment_id"]
        t_extract = data["variable_extract"]
        # 每次发送请求相当于保存接口
        if t_id != '' or t_id is not None:
            cases = Testcase.objects.filter(id=t_id)
            cases.update(t_url=t_url, t_extract=t_extract, t_type=t_type, t_body=t_body, t_params=t_params,
                         t_method=t_method, t_header=t_headers, t_environment_id=t_env_id, api_type=api_type,
                         update_time=datetime.now().strftime("%Y-%m-%d %H:%M:%S"))

        # 请求的域名
        req_api = Environment.objects.get(id=data["environment_id"])
        # 请求地址
        req_url = req_api.e_address + data["url"]

        # url处理
        if "${" in req_url and "}" in req_url:
            key = re.findall(r"\${(.+?)}", req_url)
            for a in range(len(key)):
                v_key = "${" + key[a] + "}"
                value_variable = Variable_local.objects.filter(local_name=str(v_key))
                if value_variable.count() > 0:
                    variable = value_variable[0].local_result
                    req_url = req_url.replace(v_key, variable)
                else:
                    return JsonResponse({
                        "code": 101,
                        "message": str(v_key) + "变量数据库未找到"
                    })
        logger.info("请求url=" + req_url)

        # body处理
        if data["body"] == '' or data["body"] == {}:
            payload = data["body"]
        else:
            try:
                body = data["body"]
                if "${" in body and "}" in body:
                    key = re.findall(r"\${(.+?)}", body)
                    for b in range(len(key)):
                        b_key = "${" + key[b] + "}"
                        value_variable = Variable_local.objects.filter(local_name=str(b_key))
                        if value_variable.count() > 0:
                            variable = value_variable[0].local_result
                            body = body.replace(b_key, variable)
                        else:
                            return JsonResponse({
                                "code": 101,
                                "message": str(b_key) + "变量数据库未找到"
                            })
                payload = body
            except Exception as e:
                return JsonResponse({
                    "code": 101,
                    "message": "body参数类型错误",
                    "system_log": e
                })
        logger.info("请求体=" + str(payload))

        # headers处理
        if data["headers"] == '':
            headers = data["headers"]
        else:
            try:
                head = data["headers"]
                if "${" in head and "}" in head:
                    key = re.findall(r"\${(.+?)}", head)
                    for b in range(len(key)):
                        h_key = "${" + key[b] + "}"
                        value_variable = Variable_local.objects.filter(local_name=str(h_key))
                        if value_variable.count() > 0:
                            variable = value_variable[0].local_result
                            head = head.replace(h_key, variable)
                        else:
                            return JsonResponse({
                                "code": 101,
                                "message": str(h_key) + "变量数据库未找到"
                            })
                headers = head
            except Exception as e:
                return JsonResponse({
                    "code": 101,
                    "message": "header参数类型错误",
                    "system_log": e
                })
        logger.info("请求头=" + str(headers))

        # 请求方法:1:get, 2:post, 3:put, 4:delete
        # 参数类型:1:form-data, 2:Json, 3:x-www-form-urlencoded, 4:None
        # method处理
        # params处理
        p = data["params"]
        params = {}
        if p != "":
            for item in p:
                params[item['key']] = item['value']
        logger.info("params =" + str(params))

        method = str(data['method'])
        body_type = str(data['body_type'])
        res = None
        # Get
        if method == "1":
            if body_type == "1":
                res = requests.get(req_url, params=payload, headers=headers)
                logger.info("响应结果 =" + res.text)
            if body_type == "2":
                res = requests.get(req_url, json=payload, headers=headers)
                logger.info("响应结果 =" + res.text)
            if body_type == "3":
                res = requests.get(req_url, data=payload, headers=headers)
                logger.info("响应结果 =" + res.text)
            if body_type == "4":
                res = requests.get(req_url, data=payload, headers=headers)
                logger.info("响应结果 =" + res.text)

        # Post
        if method == "2":
            if body_type == "1":
                res = requests.post(req_url, data=payload, headers=headers)
                logger.info("响应结果 =" + res.text)
            if body_type == "2":
                res = requests.post(req_url, json=payload, headers=headers)
                logger.info("响应结果 =" + res.text)
            if body_type == "3":
                res = requests.post(req_url, data=payload, headers=headers)
                logger.info("响应结果 =" + res.text)
            if body_type == "4":
                res = requests.post(req_url, data=payload, headers=headers)
                logger.info("响应结果 =" + res.text)
        # Put
        if method == "3":
            if body_type == "1":
                res = requests.put(req_url, data=payload, headers=headers)
                logger.info("响应结果 =" + res.text)
            if body_type == "2":
                res = requests.put(req_url, json=payload, headers=headers)
                logger.info("响应结果 =" + res.text)
            if body_type == "3":
                res = requests.put(req_url, data=payload, headers=headers)
                logger.info("响应结果 =" + res.text)
            if body_type == "4":
                res = requests.post(req_url, data=payload, headers=headers)
                logger.info("响应结果 =" + res.text)

        # Delete
        if method == "4":
            if body_type == "1":
                res = requests.delete(req_url, data=payload, headers=headers)
                logger.info("响应结果 =" + res.text)
            if body_type == "2":
                res = requests.delete(req_url, json=payload, headers=headers)
                logger.info("响应结果 =" + res.text)
            if body_type == "3":
                res = requests.delete(req_url, data=payload, headers=headers)
                logger.info("响应结果 =" + res.text)
            if body_type == "4":
                res = requests.delete(req_url, data=payload, headers=headers)
                logger.info("响应结果 =" + res.text)
        if res is None or res == "":
            assert_res = res.text
        else:
            assert_res = json.loads(res.text)
            # assert处理
            assert_result = []
            assert_a = data["assert"]
            assert_data = {}
            result = []
            if assert_a != "":
                for item in assert_a:
                    assert_data[item['assert_key']] = item['assert_value']
                    if assert_data[item['assert_key']] == '' or assert_data[item['assert_key']] is None:
                        assert_result.extend(result)
                    else:
                        for key in assert_data:
                            if (key in assert_res) and (assert_data[key] == str(assert_res[key])):
                                print(str(assert_res[key]))
                                assert_status = {
                                    "status": True,
                                    "assert_key": key,
                                    "assert_value": assert_data[key]
                                }
                            else:
                                assert_status = {
                                    "status": False,
                                    "assert_key": key,
                                    "assert_value": str(assert_data[key])
                                }
                        result.append(assert_status)
            assert_result.extend(result)
            logger.info("assert=" + str(assert_result))
            if assert_result:
                for ats in assert_result:
                    if Asserts.objects.filter(assert_testcase_id=t_id,
                                              assert_key=str(ats["assert_key"])).exists():
                        Asserts.objects.filter(assert_testcase_id=t_id, assert_key=str(ats["assert_key"])). \
                            update(assert_status=str(ats["status"]), assert_value=ats["assert_value"])
                    else:
                        Asserts.objects.create(assert_testcase_id=t_id, assert_key=str(ats["assert_key"]),
                                               assert_value=ats["assert_value"],
                                               assert_status=str(ats["status"]))
            elif not assert_result:
                print("删除")
                Asserts.objects.filter(assert_testcase_id=t_id).delete()

        # variable提取处理
        extract_result = []
        extract = data["variable_extract"]
        if extract is None or extract == "":
            extract_result = []
        else:
            for v in extract:
                if v["variable_name"] == "" or v["variable_data"] == "":
                    extract_dict = {
                        "message": "无参数提取"
                    }
                    extract_result.append(extract_dict)
                else:
                    # 提取变量
                    try:
                        res_result = json.loads(res.text)
                    except Exception as e:
                        logger.info(str(e))
                        pass
                    v_data = v["variable_data"].split(".")
                    try:
                        for a in v_data:
                            if "[" in a and "]" in a:
                                variable_1 = a.split('[')[0]
                                variable_2 = a.split('[')[1].split(']')[0]
                                res_result = res_result[variable_1][variable_2]
                            else:
                                res_result = res_result[a]
                        extract_dict = {
                            "variable_name": v["variable_name"],
                            "variable_data": v["variable_data"],
                            "variable_result": str(res_result),
                            "status": 1
                        }
                        extract_result.append(extract_dict)
                    except Exception as e:
                        extract_dict = {
                            "variable_name": v["variable_name"],
                            "variable_data": v["variable_data"],
                            "variable_result": "参数提取失败" + str(e),
                            "status": 0
                        }
                        extract_result.append(extract_dict)
            for e in extract_result:
                if e["status"] == 1:
                    if Variable_local.objects.filter(local_name=e["variable_name"]).count() > 0:
                        Variable_local.objects.filter(local_name=e["variable_name"]). \
                            update(local_data=e["variable_data"], local_result=e["variable_result"])
                    elif Variable_local.objects.filter(local_name=e["variable_name"]).count() == 0:
                        Variable_local.objects.filter(local_name=e["variable_name"]). \
                            create(local_name=e["variable_name"], local_data=e["variable_data"],
                                   local_result=e["variable_result"],
                                   local_user_id=data["user_id"])
            logger.info("参数提取结果 =" + str(extract_result))
            logger.info("接口响应时间 =" + str(res.elapsed.total_seconds()) + 's')
        # 返回接口请求结果,给到前端渲染
        return JsonResponse({
            "code": 200,
            "host": req_url,
            "params": params,
            "headers": headers,
            "body": payload,
            "assert_data": assert_result,
            "res_data": res.text,
            "response_time": str(res.elapsed.total_seconds()) + '秒',
            "variable": extract_result
        })

实际效果:
请求结果:
在这里插入图片描述

断言:
在这里插入图片描述

参数提取:
在这里插入图片描述

接口请求详情:
在这里插入图片描述

Vue 页面展示

配置JS文件读取接口:
在这里插入图片描述

在这里插入图片描述
case_index.vue

<template>
  <div class="app-container">
    <div>
      <div style="border-radius: 2px; float: left; width: 15%; padding-right:10px">
        <el-input v-model="filterText" placeholder="请输入要搜索的节点" style="margin-bottom:30px;" />
        <el-tree
          ref="tree"
          :data="tree_data"
          :props="defaultProps"
          :highlight-current= "true"
          class="filter-tree"
          :default-expanded-keys="[2]"
          :filter-node-method="filterNode"
          node-key="id"
          @node-click="getcase"
          >
          <span class="custom-tree-node" slot-scope="{ node, data }">
            <span v-if="data.type===0"><i :class="icon0" style="padding-right: 10px"></i>{{ node.label }}</span>
            <span v-if="data.type===1"><i :class="icon1" style="padding-right: 10px"></i>{{ node.label }}</span>
            <span v-if="data.type===2"><i :class="icon2" style="padding-right: 10px"></i>{{ node.label }}</span>
            <span v-if="data.type === 0" class="right" :class="{newStyle: 1 === number}">
            <el-dropdown trigger="click" placement="bottom">
              <span class="el-dropdown-link" style="font-size: 20px">···</span>
                <el-dropdown-menu slot="dropdown" class="header-new-drop">
                  <el-dropdown-item @click.native="new_menu">新建子菜单</el-dropdown-item>
                </el-dropdown-menu>
            </el-dropdown>
              </span>
            <span v-if="data.type === 1" class="right" :class="{newStyle: 1 === number}">
            <el-dropdown trigger="click" placement="bottom">
              <span class="el-dropdown-link" style="font-size: 20px">···</span>
                <el-dropdown-menu slot="dropdown" class="header-new-drop">
                  <el-dropdown-item @click.native="new_menu">新增</el-dropdown-item>
                  <el-dropdown-item @click.native="edit">重命名</el-dropdown-item>
                  <el-dropdown-item @click.native="input">*postman.json文件导入</el-dropdown-item>
                  <el-dropdown-item @click.native="deletepro">删除文件夹</el-dropdown-item>
                </el-dropdown-menu>
            </el-dropdown>
              </span>
            <span v-if="data.type ===2" class="right" :class="{newStyle: 2 === number}">
            <el-dropdown trigger="click" placement="bottom">
              <span class="el-dropdown-link" style="font-size: 20px">···</span>
                <el-dropdown-menu slot="dropdown" class="header-new-drop">
                  <el-dropdown-item @click.native="edit">重命名</el-dropdown-item>
                  <el-dropdown-item @click.native="copy">复制接口</el-dropdown-item>
                  <el-dropdown-item @click.native="delete_case">删除接口</el-dropdown-item>
                </el-dropdown-menu>
            </el-dropdown>
              </span>
          </span>
        </el-tree>
      </div>
      <div>
        <el-dialog
          title="新增子菜单"
          :visible.sync="dialogVisible"
           width="30%"
          :before-close="handleClose">
          <el-form :model="menu_pid">
            <el-form-item label="Type:">
               <el-select v-model="type_value">
            <el-option
              v-for="item in type_form"
              :key="item.value"
              :label="item.label"
              :value="item.value">
            </el-option>
          </el-select>
            </el-form-item>
            <el-form-item label="菜单名称">
              <el-input v-model="menu_form.label"/>
            </el-form-item>
          </el-form>
          <span slot="footer" class="dialog-footer">
            <el-button @click="dialogVisible = false">取 消</el-button>
            <el-button type="primary" @click="add_menu">确 定</el-button>
          </span>
        </el-dialog>
      </div>
      <div>
        <el-dialog
          title="重命名"
          :visible.sync="editdialogVisible"
           width="30%"
          :before-close="handleClose">
          <el-form :model="menu_form">
            <el-form-item label="menu_id">
              <el-input readonly v-model="menu_form.id"></el-input>
            </el-form-item>
            <el-form-item label="菜单名称">
              <el-input v-model="tree_name"></el-input>
            </el-form-item>
          </el-form>
          <span slot="footer" class="dialog-footer">
            <el-button @click="editdialogVisible = false">取 消</el-button>
            <el-button type="primary" @click="edit_menu">确 定</el-button>
          </span>
        </el-dialog>
      </div>
      <el-dialog
        :visible.sync="dialogImport"
        title="导入"
        v-if="dialogImport"
        width="30%"
        append-to-body>
        <div style="text-align:center">
      <!-- 此处action需为有效的任意接口——当前为官网范例接口 -->
          <el-upload
            drag
            :limit="1"
            action="https://jsonplaceholder.typicode.com/posts/"
            ref="upload"
            accept=".json"
            :file-list="fileList"
            :on-success="onSuccess"
            :on-remove="onRemove"
            :on-exceed="handleExceed"
            :headers="{ 'Content-Type': 'application/x-www-form-urlencoded' }">
            <i class="el-icon-upload"></i>
            <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
            <div class="el-upload__tip" slot="tip">
              可上传 postman 导出的 .json 文件,且只能上传 1 个文件
            </div>
          </el-upload>
        </div>
        <span slot="footer">
          <el-button @click="dialogImport = false" size="mini" type="danger">取 消</el-button>
          <el-button @click="inputcase" size="mini" type="primary">确 定</el-button>
        </span>
      </el-dialog>
      <div v-show="1 === number">
        <el-container>
            <Case_list :table="table_data" v-if="update" style="float:left; width:100%; padding-top: 0"></Case_list>
        </el-container>
      </div>
      <div v-show="2 === number">
        <el-container>
        // 数据传递给接口信息组件(:form="form_case")
          <Case_info :form="form_case" v-if="update" style="float:left; width:100%; padding-top: 0"></Case_info>
        </el-container>
      </div>
    </div>
  </div>
</template>

<script>
  import {
    addmenu, copy_case, deletecase,
    deletepeoject,
    getallTestcase,
    getCase_tree,
    getsinglecase,
    getsingleTestcaselist, uploadcase
  } from "@/api/testcase";
  import case_info from "./case_info"; //调用组件
  import case_list from "./case_list";

export default {
  name: 'case_index',
  data() {
    return {
      uploadData: [],
      fileList: [],
      dialogImport: false,
      editableTabsValue: '根目录',
      tree_name: '',
      editableTabs:[],
      tabIndex: 2,
      list: null,
      number: 1,
      filterText: '',
      expaAndList:'',
      listLoading: true,
      input_type: false,
      inputValue: '',
      menu_pid: null,
      update: true,
      icon0: 'el-icon-s-home',
      icon1: 'el-icon-folder-opened',
      icon2: 'el-icon-tickets',
      //列表
      table_data: [], //目录
      defaultProps: {
        children: 'children',
        label: 'label',
        id:"id"
      },
      tree_data: [],
      type_value: '',
        type_form: [
          {
            label: "文件夹",
            value: 1
          },
          {
            label: "接口",
            value: 2
          },
        ],
      //菜单
      m_id: null,
      menu_form:{
        label: '',
        pid: '',
        type: null,
        user_id: null,
      },
      // 用例id
      case_form: {
        menu_id: ''
      },
      // 用例详情
      form_case: [
        {
          assert_form: [
            {
              assert_key: '',
              assert_value: ''
            }
          ],
          params: [{key: '', value: ''}],
          extract: [{variable_name: '', variable_data: ''}]
        }
      ],
      params_form:{},
      editdialogVisible: false,
      dialogVisible: false,
      pidFrom: {
        id: ''
      },
    }
  },
  components: {
    "Case_info": case_info,
    "Case_list": case_list
  }
  ,
    created() {
      this.get_tree()
      this.getall()
  },
  watch: {
      filterText(val) {
        this.$refs.tree.filter(val);
      }
  },
  methods: {
      filterNode(value, tree_data) {
        if (!value) return true;
        return tree_data.label.indexOf(value) !== -1;
      },
    // 导入文件
    input(){
      this.dialogImport =true
    },
    // 移除文件
    onRemove(file) {
      this.fileList = [];
      },
    // 文件上传成功
    onSuccess(res, file, fileList) {
      let reader = new FileReader()
      reader.readAsText(file.raw)
      reader.onload = (e) => {
        this.uploadData = []
        this.uploadData = JSON.parse(e.target.result)
  }
},
    // 导入确认
    inputcase() {
      this.$confirm("导入后原数据会被覆盖,确定导入吗?", "温馨提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",}).then(() => {
    // 使用目标数据变量接收上传后的文件数据
        this.dialogImport = false
        this.uploadData.user_id = Number(localStorage.getItem("user_id"))
        this.uploadData.pid = this.pidFrom.id
        uploadcase(this.uploadData).then(res => {
          if (200 === res.data.code) {
            this.$message({
          type: "success",
          message: "导入成功!",
        })
            this.get_tree()
            this.getsinglelist()
      } else if (100 === res.data.code) {
        this.$message({
          type: "danger",
          message: "导入失败!",
        })
      }
    })
  })
},
    //刷新组件
    reload() {
     this.update = false
     this.$nextTick(() => (this.update = true))
   },
    // 获取接口目录
    get_tree(){
      getCase_tree().then(res => {
        this.tree_data = res.data.content
      })
    },
    // 获取所有测试用例
    getall(){
      getallTestcase().then(res => {
        this.table_data = res.data.content
      })
    },
    // 获取单个文件夹列表
    getsinglelist(){
      getsingleTestcaselist(this.pidFrom).then(res => {
        this.table_data = res.data.content
      })
    },
    //获取单个接口详情
    getsinglecase(){
      getsinglecase(this.case_form).then(res => {
        // 详细内容
        this.form_case = res.data
        let head = res.data.headers
        this.form_case.headers = eval(`(${head})`)
      })
    },
    // 复制接口
    copy(){
      let req = this.menu_form
      req.id = this.case_form.menu_id
      req.label = this.tree_name
      req.pid = this.m_id
      req.type = 2
      req.user_id = Number(localStorage.getItem("user_id"))
      copy_case(this.menu_form).then(res => {
        if (res.data.code === 200){
          this.$message.success("复制接口成功")
          this.get_tree()
        }else if (res.data.code === 100) {
          this.$message.error("必要参数不可为空")
        }
      })
    },
    //删除测试用例
    delete_case(){
      let data = this.case_form
      deletecase(data).then(res => {
         if (res.data.code === 200){
          this.$message({
            message: "删除接口成功",
            type: "success"
          })
           this.get_tree()
        } else if (res.data.code === 100){
          this.$message({
            message: "删除接口失败,无此接口",
            type: 'error'
          })
        }
      })
    },
    //删除文件夹
    deletepro(){
      let data = this.pidFrom
      deletepeoject(data).then(res => {
        if (res.data.code === 200){
          this.get_tree()
          this.$message({
            message: "删除文件夹成功",
            type: "success"
          })
        } else if (res.data.code === 100){
          this.$message({
            message: "必要参数不能为空",
            type: 'error'
          })
        } else if (res.data.code === 101){
          this.$message({
            message: "目录下存在文件或用例,不可删除",
            type: 'error'
          })
        } else if (res.data.code === 102){
          this.$message({
            message: "目标id不存在,无法删除",
            type: 'error'
          })
        }
      })
    },
    // 选中节点,渲染对应数据
    getcase(data){
      if (data.type === 1){
        this.number = data.type
        this.getsinglelist()
        this.reload()
        this.menu_pid = data.id
        this.pidFrom.id = data.id
        this.m_id = data.pid
        this.tree_name = data.label
        this.expaAndList = data.id
      }
      else if (data.type === 2){
        this.number = data.type
        this.reload()
        this.case_form.menu_id = data.id
        this.pidFrom.id = data.id
        this.tree_name = data.label
        this.m_id = data.pid
        this.getsinglecase()
        this.expaAndList = data.id
      }
      else if (data.type === 0){
        this.pidFrom.id = data.id
        this.number = 1
        this.reload()
        this.getall()
      }
    },
    new_menu() {
      this.dialogVisible = true
    },
    add_menu(){
      this.menu_form.type = this.type_value
      this.menu_form.pid = this.pidFrom.id
      this.menu_form.user_id = Number(localStorage.getItem("user_id"))
      addmenu(this.menu_form).then(res => {
        if (res.data.code === 200){
          this.$message({
          message: '创建子菜单成功',
          type: 'success'
        })
          this.dialogVisible = false
          this.get_tree()
        } else if (res.data.code === 100){
          this.dialogVisible = true
          this.$message.error("菜单名称不可为空")
        }else if (res.data.code === 101){
          this.dialogVisible = true
          this.$message.error("名称已存在,请重新输入")
        }
      })
    },
    edit(){
      this.menu_form.id = this.pidFrom.id
      this.editdialogVisible = true
    },
    edit_menu(){
      let req = this.menu_form
      req.id = this.pidFrom.id
      req.label = this.tree_name
      req.pid = this.m_id
      req.user_id = Number(localStorage.getItem("user_id"))
      addmenu(req).then(res => {
        if (res.data.code === 200){
          this.$message({
          message: '重命名成功',
          type: 'success'
        })
          this.editdialogVisible = false
          this.get_tree()
        } else if (res.data.code === 100){
          this.editdialogVisible = true
          this.$message.error("菜单名称不可为空")
        }else if (res.data.code === 101){
          this.editdialogVisible = true
          this.$message.error("名称已存在,请重新输入")
        }
      })
    },
    handleClose(done) {
      done()
      },
  }
}
</script>

<style scoped>
  .el-button{
    padding: 4px;
  }
  .custom-tree-node {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 14px;
    padding-right: 8px;
  }
</style>

case_info.vue

<template>
    <div class="form">
      <div>
        <div>
        <el-form v-model="form">
          <div class="global_box" style="padding: 8px; height: 100%; width: 100%">
            <div style="padding-left: 10px; font-size: 20px">{{form.name}}</div>
            <el-select v-model="form.api_type" placeholder="接口类型" style="padding: 10px">
            <el-option
              v-for="item in api_type"
              :key="item.api_type_value"
              :label="item.label"
              :value="item.api_type_value">
            </el-option>
          </el-select>
          <el-select v-model="form.method" placeholder="method" style="padding: 10px">
            <el-option
              v-for="item in method_form"
              :key="item.method_value"
              :label="item.label"
              :value="item.method_value">
            </el-option>
          </el-select>
           <el-select v-model="form.environment_id" placeholder="environment">
            <el-option
              v-for="env in env_form"
              :key="env.environment_id"
              :label="env.environment_name"
              :value="env.environment_id">
            </el-option>
          </el-select>
          <el-input v-model="form.url" id="url" placeholder="接口URL" style="width: 500px; padding: 10px"></el-input>
          <el-button type="primary" style="padding: 10px" icon="el-icon-s-promotion" @click="send">Send</el-button>
            <el-button type="success" style="padding: 10px" icon="el-icon-s-tools" @click="get_env_all">环境变量</el-button>
            <el-button type="primary" style="padding: 12px; float: right" icon="el-icon-s-tools" @click.native="save_testcase">保存</el-button>
          </div>
          <div style="height: 100%; width: 100%" class="global_box">
          <el-tabs v-model="req_activeName" value="params" type="border-card">
            <el-tab-pane style="font-weight:bolder" label="Params" name="Params">
                <div>
                  <el-table :data="form.params">
                    <template slot="empty">
                        <el-button type="success" icon="el-icon-circle-plus-outline" @click="add_params">Add</el-button>
                      </template>
                    <el-table-column label="key">
                      <template slot-scope="scope">
                        <el-input id="params_key" v-model="scope.row.key"></el-input>
                      </template>
                    </el-table-column>
                    <el-table-column label="value">
                      <template slot-scope="scope">
                        <el-input id="params_value" v-model="scope.row.value"></el-input>
                      </template>
                    </el-table-column>
                    <el-table-column>
                      <template slot-scope="scope">
                      <el-button type="success" icon="el-icon-circle-plus-outline" @click="add_params"></el-button>
                      <el-button type="danger" icon="el-icon-remove-outline" @click.native.prevent="del_params(scope.$index, scope.row)"></el-button>
                        </template>
                      </el-table-column>
                  </el-table>
                </div>
            </el-tab-pane>
            <el-tab-pane label="Headers" name="Headers">
              <vue-json-editor
                v-model="form.headers"
                :showBtns="false"
                :mode="'code'"
                style="height: 100%"
                />
            </el-tab-pane>
            <el-tab-pane label="Body" name="Body">
              <el-radio-group v-model="form.body_type" style="padding-block-end: 10px">
                <el-radio :label="4" value="4">None</el-radio>
                <el-radio :label="1" value="1">form-data</el-radio>
                <el-radio :label="2" value="2">JSON</el-radio>
                <el-radio :label="3" value="3">x-www-form-urlencoded</el-radio>
              </el-radio-group>
              <vue-json-editor
                v-model="form.body"
                :showBtns="false"
                :mode="'code'"
                style="height: 100%"
                />
            </el-tab-pane>
            <el-tab-pane label="Assert" name="Assert">
              <div>
                  <el-table :data="form.assert_form">
                    <template slot="empty">
                        <el-button type="success" icon="el-icon-circle-plus-outline" @click="add_assert">Add</el-button>
                      </template>
                    <el-table-column label="字段名">
                      <template slot-scope="scope">
                        <el-input v-model="scope.row.assert_key"></el-input>
                      </template>
                    </el-table-column>
                    <el-table-column label="结果">
                      <template slot-scope="scope">
                        <el-input v-model="scope.row.assert_value"></el-input>
                      </template>
                    </el-table-column>
                    <el-table-column>
                      <template slot-scope="scope">
                      <el-button type="success" icon="el-icon-circle-plus-outline" @click="add_assert"></el-button>
                      <el-button type="danger" icon="el-icon-remove-outline" @click.native.prevent="del_assert(scope.$index, scope.row)"></el-button>
                        </template>
                    </el-table-column>
                  </el-table>
                </div>
            </el-tab-pane>
            <el-tab-pane label="参数提取" name="loacl_Variable">
              <div>
                  <el-table :data="form.extract">
                    <template slot="empty">
                        <el-button type="success" icon="el-icon-circle-plus-outline" @click="add_extract_form">Add</el-button>
                  </template>
                    <el-table-column label="变量名称">
                      <template slot-scope="scope">
                        <el-input v-model="scope.row.variable_name"></el-input>
                      </template>
                    </el-table-column>
                    <el-table-column label="变量路径">
                      <template slot-scope="scope">
                        <el-input v-model="scope.row.variable_data" placeholder="res.content"></el-input>
                      </template>
                    </el-table-column>
                    <el-table-column>
                      <template slot-scope="scope">
                      <el-button type="success" icon="el-icon-circle-plus-outline" @click="add_extract_form"></el-button>
                      <el-button type="danger" icon="el-icon-remove-outline" @click.native.prevent="del_extract_form(scope.$index, scope.row)"></el-button>
                        </template>
                    </el-table-column>
                  </el-table>
                </div>
            </el-tab-pane>
          </el-tabs>
          </div>
          <div style="height: 100%; width: 100%" class="global_box">
<!-- <el-title>响应结果</el-title>-->
          <el-tabs v-model="res_activeName" type="border-card">
            <el-tab-pane label="Response body" name="body">
              <vue-json-editor
                v-model="res_form.res_data"
                :showBtns="false"
                :mode="'code'"
                style="height: 100%"
              >
              </vue-json-editor>
            </el-tab-pane>
            <el-tab-pane label="Assert-result" name="third">
              <div>
                  <el-table :data="res_form.assert_data">
                    <el-table-column label="字段名">
                      <template slot-scope="scope">
                        <el-input readonly v-model="scope.row.assert_key"></el-input>
                      </template>
                    </el-table-column>
                    <el-table-column label="">
                      <template slot-scope="scope">
                        <el-input readonly v-model="scope.row.assert_value"></el-input>
                      </template>
                    </el-table-column>
                    <el-table-column label="结果">
                      <template slot-scope="scope">
                        <el-input readonly v-model="scope.row.status"></el-input>
                      </template>
                    </el-table-column>
                  </el-table>
                </div>
            </el-tab-pane>
            <el-tab-pane label="RES-参数提取" name="fourth">
              <div>
                  <el-table :data="res_form.variable">
                    <el-table-column label="变量名称">
                      <template slot-scope="scope">
                        <el-input readonly v-model="scope.row.variable_name"></el-input>
                      </template>
                    </el-table-column>
                    <el-table-column label="变量路径">
                      <template slot-scope="scope">
                        <el-input readonly v-model="scope.row.variable_data" placeholder=""></el-input>
                      </template>
                    </el-table-column>
                    <el-table-column label="变量结果">
                      <template slot-scope="scope">
                        <el-input readonly v-model="scope.row.variable_result" placeholder=""></el-input>
                      </template>
                    </el-table-column>
                  </el-table>
                </div>
            </el-tab-pane>
            <el-tab-pane label="接口请求详情" name="fifth">
              <div style="height: 282px; overflow: scroll">
                <p>接口响应时间:{{res_form.response_time}}</p>
                <p>[ url ] ==>  {{res_form.host}}</p>
                <p>[ params ] ==>  {{res_form.params}}</p>
                <p>[ headers ] ==>  {{res_form.headers}}</p>
                <p>[ body ] ==>  {{res_form.body}}</p>
                <p>[ response ] ==>  {{res_form.res_data}}</p>
              </div>
            </el-tab-pane>
          </el-tabs>
          </div>
        </el-form>
           <div>
              <el-dialog
                title="环境"
                :visible.sync="dialogVisible"
                width="70%"
                >
        <div>
          <div style="padding-block-end: 10px">
            <el-input v-model="env_page.env_name" id="task_name" placeholder="请输入环境名称" style="width: 800px; padding-right: 10px;"></el-input>
          <el-button type="primary" @click="get_env_all" size="medium" style="padding: 10px;">搜索</el-button>
          </div>
          <el-table
            :data="table_data"
            element-loading-text="Loading"
            border
            fit
            highlight-current-row
            >
        <el-table-column align="center" label="ID">
          <template slot-scope="scope">
            {{ scope.row.environment_id }}
          </template>
        </el-table-column>
        <el-table-column label="环境名称"  width="280px">
          <template slot-scope="scope">
            {{ scope.row.environment_name }}
          </template>
        </el-table-column>
        <el-table-column label="环境地址" width="280px">
          <template slot-scope="scope">
            {{ scope.row.environment_address }}
          </template>
        </el-table-column>
        <el-table-column class-name="status-col" label="描述" align="center">
           <template slot-scope="scope">
            {{ scope.row.environment_e_describe }}
          </template>
        </el-table-column>
        <el-table-column label="更新人" align="center">
          <template slot-scope="scope">
            {{ scope.row.username }}
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
            background
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
            :current-page="env_page.current_page"
            :page-sizes="[6]"
            :page-size="env_page.size_page"
            layout="total, sizes, prev, pager, next, jumper"
            :total="env_case_total"
            style="float: left; padding: 10px"
      >
      </el-pagination>
  </div>
              </el-dialog>
            </div>
        </div>
      </div>
    </div>
</template>
<script>
import vueJsonEditor from 'vue-json-editor'
import {get_envall, getenvlist} from "@/api/environment";
import {saverequest, sendrequest} from "@/api/testcase";
import Link from "../../layout/components/Sidebar/Link";
export default {
  name: "case_info",
  props: {
    form: [Array, Object] // 接收case_index.vue传来的数据
  },
    data() {
      return {
        table_data: [],
        dialogVisible: false,
        req_activeName: 'Params',
        res_activeName: 'body',
        url_input: '',
        method: '',
        local_variable_form: [
          {
            local_variable_name: '',
            local_variable_data: '',
            local_variable_result: '',
            local_variable_description: ''
          }
        ],
        method_form: [
          {
            label: "GET",
            method_value: 1
          },
          {
            label: "POST",
            method_value: 2
          },
          {
            label: "PUT",
            method_value: 3
          },
          {
            label: "DELETE",
            method_value: 4
          }
        ],
        api_type: [
          {
            label: "普通接口",
            api_type_value: 1
          }
        ],
        env_value: '',
        env_form: [
          {
            environment_id: '',
            environment_name: '',
          }
        ],
        // 接口请求
        req_form: {
          url: '',
          environment_id: '',
          headers: {},
          body: {},
          params: [],
          method: '',
          body_type: '',
          assert: [],
          variable_extract: []
        },
        // 接口返回
        res_form: [
          {
            res_data: {},
            variable_extract: [
              {
                variable_name: '',
                variable_data: ''
              }
            ],
            assert_data: [
              {
                assert_key: '',
                assert_value: '',
                status: ''
              }
            ],
            variable: [{
              variable_name: '',
              variable_data: '',
              variable_result: ''
            }]
          }
        ],
        env_page: {
          env_name: "",
          current_page: 1,
          size_page: 6
        },
        env_case_total: null
      }
    },
  components: {
    Link,
    vueJsonEditor
  },
  created() {
    this.get_env()
  },
  methods: {
       // 页签-条/页 跳转
    handleSizeChange(val) {
      this.env_page.size_page = val
      this.get_env_all()
    },
    // 底部页签跳转
    handleCurrentChange(val) {
      this.env_page.current_page = val
      this.get_env_all()
    },
      get_env_all(){
      this.dialogVisible = true
        get_envall(this.env_page).then(res => {
          this.table_data = res.data.content
          this.env_case_total = res.data.case_total
          this.env_page.current_page = res.data.current_page
          this.env_page.size_page = res.data.size_page
        })
      },
    // 发送请求
    send(){
      let req = this.req_form
      req.testcase_id = this.form.id
      req.user_id = Number(localStorage.getItem("user_id"))
      req.url = this.form.url
      req.environment_id = this.form.environment_id
      req.headers = this.form.headers
      req.body = this.form.body
      req.api_type = this.form.api_type
      req.params = this.form.params
      req.method = this.form.method
      req.body_type = this.form.body_type
      req.assert = this.form.assert_form
      req.variable_extract = this.form.extract
      sendrequest(this.req_form).then(res => {
        if (res.data.code === 200){
          this.res_form = res.data
          let res_body = res.data.res_data
          this.res_form.res_data = eval(`(${res_body})`)
        }
      })
    },
    add_params(){
      let list = {
        key: '',
        value: ''
      }
      this.form.params.push(list)
    },
    // 删除Params
    del_params(index, row){
        this.form.params.splice(index,1)
    },
    // 新增Assert
    add_assert(){
      let list = {
        assert_key: '',
        assert_value: ''
      }
      this.form.assert_form.push(list)
    },
    // 删除Assert
    del_assert(index, row){
      this.form.assert_form.splice(index,1)
    },
    // 新增本地变量
    add_extract_form(){
      let list = {
        variable_name: '',
        variable_value: ''
      }
      this.form.extract.push(list)
    },
    // 删除本地变量
    del_extract_form(index, row){
        this.form.extract.splice(index,1)
    },
    get_env(){
      getenvlist().then(res =>{
        this.env_form = res.data.content
      })
    },
    save_testcase(){
      let req = this.req_form
      req.testcase_id = this.form.id
      req.url = this.form.url
      req.environment_id = this.form.environment_id
      req.headers = JSON.parse(JSON.stringify(this.form.headers))
      req.body = JSON.parse(JSON.stringify(this.form.body))
      req.params = JSON.parse(JSON.stringify(this.form.params))
      req.api_type = this.form.api_type
      req.method = this.form.method
      req.body_type = this.form.body_type
      req.assert = JSON.parse(JSON.stringify(this.form.assert_form))
      req.variable_extract = JSON.parse(JSON.stringify(this.form.extract))
      saverequest(this.req_form).then(res => {
        if (res.data.code === 200){
          this.$message.success("保存接口成功")
        }
      })
    }
  }
}
</script>

<style lang="scss">
  .global_box {
    max-width: 100%;
    max-height: 100%;
    box-shadow: 0 0 0.01vw #000000 inset;
    padding:0;
}

.jsoneditor-outer{
   height: 280px !important;
  }
.el-dialog__body{
  height: 100%;
  padding: 50px 20px
}

</style>

具体效果:
在这里插入图片描述
疑问可在评论区评论,有空就会回复

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

测开小林

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值