{{ item }}
20 |{{ log }}
15 |{{ log }}
15 |{{ log }}
19 |" + e.data + "
{{ item }}
84 |' + "耗时:" + this.apiData.consume_time[item.dataIndex] + "ms" + '
' + 62 | '' + "用例名:" + this.apiData.case_name[item.dataIndex] + '
' + 63 | '' + "请求时间:" + this.apiData.create_time[item.dataIndex] + '
' + 64 | '' + "请求类型:" + this.apiData.request_type[item.dataIndex] + '
' + 65 | '' + "返回Code:" + this.apiData.response_code[item.dataIndex] + '
' 66 | ; 67 | }); 68 | return result; 69 | } 70 | }, 71 | legend: { 72 | data: ["耗时"] 73 | }, 74 | toolbox: { 75 | show: true, 76 | feature: { 77 | mark: { 78 | show: true 79 | }, 80 | dataView: { 81 | show: true, 82 | readOnly: true 83 | }, 84 | magicType: { 85 | show: false, 86 | type: ["line", "bar", "stack", "tiled"] 87 | }, 88 | restore: { 89 | show: true 90 | }, 91 | saveAsImage: { 92 | show: true 93 | } 94 | } 95 | }, 96 | calculable: true, 97 | xAxis: [ 98 | { 99 | name: "运行次数", 100 | type: "category", 101 | boundaryGap: false, 102 | data: this.apiData.num, 103 | nameLocation: "end" 104 | } 105 | ], 106 | yAxis: [ 107 | { 108 | name: "耗时", 109 | type: "value", 110 | axisLabel: { 111 | formatter: '{value} ms' 112 | } 113 | } 114 | ], 115 | series: [ 116 | { 117 | name: "耗时", 118 | type: "line", 119 | smooth: true, 120 | itemStyle: { 121 | normal: { 122 | areaStyle: { 123 | type: "default" 124 | } 125 | } 126 | }, 127 | data: this.apiData.consume_time 128 | } 129 | ] 130 | }; 131 | 132 | // 使用刚指定的配置项和数据显示图表。 133 | this.myChart.setOption(option); 134 | }, 135 | 136 | 137 | //todo 登录提示 138 | /*查询对应记录下的详细运行日志记录*/ 139 | queryDetailData(logId) { 140 | /*对logId进行处理兼容es*/ 141 | logId = logId.replace(/\-/g, ""); 142 | fetch('../wholog/queryLogData', 143 | { 144 | method: 'POST', 145 | credentials: "same-origin", 146 | headers: { 147 | 'Accept': 'application/json, text/plain, */*', 148 | 'Content-Type': 'application/json', 149 | 'Authorization': "JWT " + this.jwtHeader() 150 | }, 151 | body: JSON.stringify({logId: logId}) 152 | }).then((response) => { 153 | /*判断请求状态码*/ 154 | if (response.status !== 200) { 155 | if (response.status === 401) { 156 | this.openLoginPopup(); 157 | /*判断未登录时 去打开登录提示*/ 158 | } else { 159 | console.log("请求失败,状态码为:" + response.status); 160 | } 161 | return; 162 | } else { 163 | return response.json(); 164 | } 165 | }).then((json) => { 166 | console.log("请求成功,打开dialog"); 167 | this.logDialog.menus = json['data']; 168 | this.openDialog(); 169 | }).catch((err) => { 170 | console.log("请求wholog/queryLogData出错:" + err); 171 | }); 172 | 173 | }, /*queryDetailData end*/ 174 | 175 | /*打开和关闭日志运行详情对话框*/ 176 | openDialog() { 177 | this.logDialog.switch = true; 178 | }, 179 | closeDialog() { 180 | this.logDialog.switch = false; 181 | }, 182 | 183 | }, 184 | 185 | watch: { //数据变化时自动重画,在控制台修改message,会自动重画 186 | message: () => { 187 | 188 | this.draw(); 189 | } 190 | }, 191 | mounted() { 192 | this.refreshJwtToken(); 193 | this.$nextTick(() => { 194 | this.myChart = echarts.init(document.getElementById('main-chart')); //初始化echarts实例 195 | this.draw(); 196 | this.myChart.on('click', (params) => { 197 | //打开对话框,查询数据 198 | this.openDialog(); 199 | this.queryDetailData(this.apiData.log_id[params.dataIndex]); 200 | }); 201 | }) 202 | }, 203 | 204 | 205 | }; 206 | 207 | -------------------------------------------------------------------------------- /arbiter-web/arbiter/core/views.py: -------------------------------------------------------------------------------- 1 | import codecs 2 | import json 3 | import os 4 | import stat 5 | import shutil 6 | import time 7 | import git 8 | from django.core.files import File 9 | from django.http import HttpResponse, JsonResponse 10 | from django.shortcuts import render 11 | from rest_framework import permissions 12 | from rest_framework.authtoken.models import Token 13 | from rest_framework.decorators import api_view, permission_classes 14 | from rest_framework.permissions import IsAuthenticated 15 | from rest_framework.views import APIView 16 | 17 | from arbiter.core.models import CaseList 18 | from arbiter.models import Case_List, Git_Info 19 | 20 | 21 | # 登录 22 | def login(request): 23 | return render(request, 'case/login.html') 24 | 25 | 26 | def index(request): 27 | return render(request, 'case/index.html') 28 | 29 | 30 | class restful(APIView): 31 | # 获取测试用例树 32 | def __init__(self, **kwargs): 33 | super().__init__(**kwargs) 34 | self.body = None 35 | 36 | @api_view(['POST']) 37 | @permission_classes([permissions.AllowAny, ]) 38 | def get_case_list(self): 39 | try: 40 | cases_results = Case_List.objects.filter(name="arbiter_cases").first().data 41 | return JsonResponse(cases_results) 42 | except AttributeError: 43 | cases_results = CaseList.getList() 44 | Case_List.objects.create(name="arbiter_cases", data=cases_results) 45 | return JsonResponse(cases_results) 46 | 47 | # 获取测试用例GIT工程 48 | @api_view(['POST']) 49 | @permission_classes([permissions.AllowAny, ]) 50 | def get_caseobj(self): 51 | case_path = os.getenv("CASEPATH") 52 | json_obj = json.loads(self.body) 53 | if Git_Info.objects.count() > 0: 54 | info = Git_Info.objects.get() 55 | info.git_url = json_obj.get('url') 56 | info.user_name = json_obj.get("git_username") 57 | info.password = json_obj.get("git_password") 58 | info.save() 59 | 60 | def set_rw(operation, name, exc): 61 | os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) 62 | os.remove(name) 63 | return True 64 | 65 | shutil.rmtree('../arbiter-cases', onerror=set_rw) 66 | else: 67 | Git_Info.objects.create(user_name=json_obj.get("git_username"), password=json_obj.get("git_password"), 68 | git_url=json_obj.get('url')) 69 | 70 | repo = git.Repo.clone_from(json_obj.get('url'), '../arbiter-cases/' + case_path.split('/')[0], branch='master') 71 | response_data = {'success': True} 72 | if Case_List.objects.count() > 0: 73 | case_list = Case_List.objects.get() 74 | case_list.name = "arbiter_cases" 75 | case_list.data = CaseList.getList() 76 | case_list.save() 77 | else: 78 | Case_List.objects.create(name="arbiter_cases", data=CaseList.getList()) 79 | return JsonResponse(response_data) 80 | 81 | 82 | # 下列接口需要登录验证 83 | class auth_restful(APIView): 84 | # 设置permission_classes为必须登陆才能访问下列接口 85 | permission_classes = (IsAuthenticated,) 86 | 87 | # 获取用户信息 88 | def __init__(self, **kwargs): 89 | super().__init__(**kwargs) 90 | self.user = None 91 | self.method = None 92 | self.body = None 93 | 94 | @api_view(['POST']) 95 | def get_user_detail(self): 96 | response_data = {'username': self.user.username, 97 | 'role': list(self.user.groups.values_list('name', flat=True))} 98 | return JsonResponse(response_data) 99 | 100 | # 注销 101 | @api_view(['GET']) 102 | def logout(self): 103 | Token.objects.get(user_id=self.user.id).delete() 104 | Token.objects.create(user_id=self.user.id) 105 | response_data = {'success': True} 106 | return JsonResponse(response_data, content_type="application/json") 107 | 108 | # 复制文件方法 109 | @api_view(['POST']) 110 | def copy_case_file(self): 111 | case_path = os.getenv("CASEPATH") 112 | # 获取发送的请求 113 | json_str = self.body 114 | json_obj = json.loads(json_str) 115 | git_path = '../arbiter-cases/' + case_path.split("/")[0] 116 | root_path = '../arbiter-cases/' + case_path + '/' 117 | old_case_path = json_obj.get('oldPath') 118 | new_case_path = json_obj.get('newPath') 119 | shutil.copyfile(root_path + old_case_path, 120 | root_path + new_case_path) 121 | repo = git.Repo(git_path) 122 | repo_index = repo.index 123 | repo_index.add([case_path.split("/")[1] + "/" + new_case_path]) 124 | repo_index.commit(self.user.username + "复制文件" + old_case_path + "到" + new_case_path) 125 | # 获取远程仓库 126 | remote = repo.remote() 127 | remote.pull() 128 | # 推送本地修改到远程仓库 129 | remote.push() 130 | # 同步最新用例列表到数据库 131 | case_list = Case_List.objects.get() 132 | case_list.name = "arbiter_cases" 133 | case_list.data = CaseList.getList() 134 | case_list.save() 135 | return HttpResponse(json.dumps({"result": 'ok'}), content_type="application/json") 136 | # 复制文件方法 137 | 138 | @api_view(['POST']) 139 | def delete_case_file(self): 140 | case_path = os.getenv("CASEPATH") 141 | # 获取发送的请求 142 | json_str = self.body 143 | json_obj = json.loads(json_str) 144 | git_path = '../arbiter-cases/' + case_path.split("/")[0] 145 | root_path = '../arbiter-cases/' + case_path + '/' 146 | delete_case_path = case_path = json_obj.get('deleteFilePath') 147 | os.remove(root_path + delete_case_path) 148 | repo = git.Repo(git_path) 149 | repo.git.add(update=True) 150 | repo_index = repo.index 151 | repo_index.commit(self.user.username + "删除文件" + delete_case_path) 152 | # 获取远程仓库 153 | remote = repo.remote() 154 | remote.pull() 155 | # 推送本地修改到远程仓库 156 | remote.push() 157 | # 同步最新用例列表到数据库 158 | case_list = Case_List.objects.get() 159 | case_list.name = "arbiter_cases" 160 | case_list.data = CaseList.getList() 161 | case_list.save() 162 | return HttpResponse(json.dumps({"result": 'ok'}), content_type="application/json") 163 | 164 | # 保存文件方法 165 | @api_view(['POST']) 166 | def save_case_file(self): 167 | case_path = os.getenv("CASEPATH") 168 | case_path_obj = case_path.split('/')[0] 169 | # 获取发送的请求 170 | json_str = self.body 171 | json_obj = json.loads(json_str) 172 | case_path = json_obj.get('casepath').split(':')[0].replace('.', '/') + '.py' 173 | time_str = time.strftime("%Y-%m-%d %H_%M_%S") 174 | # rename 原文件+时间格式(2017-07-20 18_34_48) 175 | os.rename('../arbiter-cases/' + case_path_obj + '/' + case_path, 176 | '../arbiter-cases/' + case_path_obj + '/' + case_path + '_' + time_str + '.history') 177 | # 使用codecs解决乱码问题 178 | with codecs.open('../arbiter-cases/' + case_path_obj + '/' + case_path, 'w', 'utf-8') as f: 179 | mfile = File(f) 180 | mfile.write(json_obj.get('content')) 181 | mfile.flush() 182 | mfile.seek(0) 183 | mfile.close() 184 | if mfile.closed: 185 | result = 'ok' 186 | repo = git.Repo('../arbiter-cases/' + case_path_obj) 187 | repo.git.add(update=True) 188 | repo_index = repo.index 189 | repo_index.commit(self.user.username + "修改文件" + case_path) 190 | # 获取远程仓库 191 | remote = repo.remote() 192 | remote.pull() 193 | # 推送本地修改到远程仓库 194 | remote.push() 195 | # 同步最新用例列表到数据库 196 | case_list = Case_List.objects.get() 197 | case_list.name = "arbiter_cases" 198 | case_list.data = CaseList.getList() 199 | case_list.save() 200 | return HttpResponse(json.dumps({"result": result}), content_type="application/json") 201 | --------------------------------------------------------------------------------