Skip to content

Commit

Permalink
refactor: impl sidebar by recursive
Browse files Browse the repository at this point in the history
feat(fe): mock project crud
  • Loading branch information
trumpchifan committed Mar 4, 2024
1 parent d4f7c35 commit 9481ac6
Show file tree
Hide file tree
Showing 9 changed files with 466 additions and 40 deletions.
8 changes: 8 additions & 0 deletions FasterRunner/customer_swagger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from drf_yasg.inspectors import SwaggerAutoSchema


class CustomSwaggerAutoSchema(SwaggerAutoSchema):
def get_tags(self, operation_keys=None):
if hasattr(self.view, 'swagger_tag'):
return [self.view.swagger_tag]
return super().get_tags(operation_keys)
21 changes: 20 additions & 1 deletion mock/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,32 @@ class Meta:
"api_id",
"api_desc",
"api_name",
"creator",
"updater",
"create_time",
"update_time",
]
read_only_fields = [
"api_id",
"creator",
"updater",
"create_time",
"update_time",
]


class MockProjectSerializer(serializers.ModelSerializer):
class Meta:
model = MockProject
fields = ["project_id", "project_name", "project_desc", "is_active"]
fields = [
"id",
"project_id",
"project_name",
"project_desc",
"is_active",
"creator",
"updater",
"create_time",
"update_time",
]
read_only_fields = ["id", "creator", "updater", "create_time", "update_time", "project_id"]
29 changes: 27 additions & 2 deletions mock/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@
import types
import uuid

from django_filters import rest_framework as filters
from django_filters.rest_framework import DjangoFilterBackend
from drf_yasg.utils import swagger_auto_schema
from rest_framework import status, viewsets
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView

from FasterRunner.customer_swagger import CustomSwaggerAutoSchema
from .models import MockAPI, MockAPILog, MockProject
from .serializers import MockAPISerializer, MockProjectSerializer

Expand All @@ -32,6 +36,8 @@ def execute(req, resp):


class MockAPIViewset(viewsets.ModelViewSet):
swagger_tag = '项目下的Mock API CRUD'
swagger_schema = CustomSwaggerAutoSchema
queryset = MockAPI.objects.all()
serializer_class = MockAPISerializer
authentication_classes = []
Expand Down Expand Up @@ -104,7 +110,7 @@ def process(path, project_id, request: Request):
"mock_server_full_path": request.get_full_path(),
"body": request.data,
"headers": request.headers._store,
"query_params": request.query_params
"query_params": request.query_params,
}
logger.debug(f"request_obj: {json.dumps(request_obj, indent=4)}")
mock_api = MockAPI.objects.get(
Expand Down Expand Up @@ -151,28 +157,47 @@ def process(path, project_id, request: Request):
class MockAPIView(APIView):
authentication_classes = []

@swagger_auto_schema(tags=["外部调用的mockapi"])
def get(self, request: Request, project_id: str, path: str) -> Response:
return self.process_request(path, project_id, request)

@swagger_auto_schema(tags=["外部调用的mockapi"])
def post(self, request: Request, project_id: str, path: str) -> Response:
return self.process_request(path, project_id, request)

@swagger_auto_schema(tags=["外部调用的mockapi"])
def put(self, request: Request, project_id: str, path: str) -> Response:
return self.process_request(path, project_id, request)

@swagger_auto_schema(tags=["外部调用的mockapi"])
def delete(self, request: Request, project_id: str, path: str) -> Response:
return self.process_request(path, project_id, request)

def process_request(self, path: str, project_id: str, request: Request) -> Response:
return process(path, project_id, request)


class MockProjectFilter(filters.FilterSet):
project_name = filters.CharFilter(lookup_expr="icontains")
project_desc = filters.CharFilter(lookup_expr="icontains")
creator = filters.CharFilter(lookup_expr="exact")
# page = filters.CharFilter(lookup_expr="page")

class Meta:
model = MockProject
fields = ["project_name", "project_desc", "creator"]


class MockProjectViewSet(viewsets.ModelViewSet):
swagger_tag = 'Mock Project CRUD'
swagger_schema = CustomSwaggerAutoSchema
queryset = MockProject.objects.all()
serializer_class = MockProjectSerializer
authentication_classes = []
filter_backends = [DjangoFilterBackend]
filterset_class = MockProjectFilter

def create(self, request):
def create(self, request, *args, **kwargs):
data = request.data.copy()
data["project_id"] = str(uuid.uuid4().hex)
serializer = MockProjectSerializer(data=data)
Expand Down
14 changes: 14 additions & 0 deletions web/src/pages/common/layout/CommonLayout.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<template>
<div class="layout">
<main>
<router-view></router-view> <!-- 子路由在这里渲染 -->
</main>
</div>
</template>

<script>
export default {
name: 'CommonLayout',
// ...
};
</script>
62 changes: 28 additions & 34 deletions web/src/pages/home/components/Side.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<template>

<el-menu
class="common-side-bar"
:default-active="$store.state.routerName"
Expand All @@ -8,47 +7,42 @@
active-text-color="#318DF1"
@select="select"
>
<el-menu-item index="ProjectList">
<i class="iconfont">&#xe631;</i>&nbsp;&nbsp;首 页
</el-menu-item>

<!-- <el-submenu index="ApiTest">
<template slot="title">
<i class="el-icon-view"></i>
<span slot="title">接口自动化</span>
</template>-->

<!--<el-menu-item-group>-->
<el-menu-item v-for="item of side_menu" :index="item.url" :key="item.url"
:disabled="$store.state.routerName === 'ProjectList' || $route.path === '/fastrunner/project_list'">
<span class="iconfont" v-html="item.code"></span>&nbsp;&nbsp;{{ item.name }}
</el-menu-item>
<!-- </el-menu-item-group>
</el-submenu>-->
<!-- <el-menu-item index="Pressure" disabled>
&nbsp;<span class="iconfont">&#xe61f;</span>&nbsp;&nbsp;压力测试
</el-menu-item>-->


<sidebar-item
v-for="item in side_menu"
:key="item.url"
:item="item"
/>
</el-menu>
</template>

<script>
import SidebarItem from "@/pages/home/components/SidebarItem.vue";
export default {
name: "Side",
components: {SidebarItem},
data() {
return {
side_menu: [
{name: "项目概况", url: "ProjectDetail", code: "&#xe64a;"},
{name: "API 模板", url: "RecordApi", code: "&#xe74a;"},
{name: "测试用例", url: "AutoTest", code: "&#xe6da;"},
{name: "配置管理", url: "RecordConfig", code: "&#xee32;"},
{name: "全局变量", url: "GlobalEnv", code: "&#xe692;"},
{name: "驱动代码", url: "DebugTalk", code: "&#xe7ca;"},
{name: "定时任务", url: "Task", code: "&#xe61e;"},
{name: "历史报告", url: "Reports", code: "&#xe66e;"},
{name: "Mock", url: "Reports", code: "&#xe66e;"}
],
{name: "首页", url: "ProjectList", icon: 'el-icon-s-home'},
{name: "项目概况", url: "ProjectDetail", icon: 'el-icon-s-cooperation'},
{name: "API 模板", url: "RecordApi", icon: 'el-icon-s-claim'},
{name: "测试用例", url: "AutoTest", icon: 'el-icon-s-operation'},
{name: "配置管理", url: "RecordConfig", icon: 'el-icon-s-tools'},
{name: "全局变量", url: "GlobalEnv", icon: 'el-icon-s-custom'},
{name: "驱动代码", url: "DebugTalk", icon: 'el-icon-s-platform'},
{name: "定时任务", url: "Task", icon: 'el-icon-timer'},
{name: "历史报告", url: "Reports", icon: 'el-icon-s-data'},
{
name: "Mock",
url: "MockServer",
icon: 'el-icon-s-help',
children: [ // 子菜单项
{name: "Mock 项目", url: "MockProject", icon: 'el-icon-folder-opened'},
{name: "Mock APIs", url: "MockAPIs", icon: 'el-icon-document-copy'}
]
}
]
}
},
methods: {
Expand All @@ -64,7 +58,7 @@ export default {
}
},
mounted() {
if(this.$store.state.show_hosts){
if (this.$store.state.show_hosts) {
this.side_menu.splice(5, 0, {name: "Hosts管理", url: "HostIP", code: "&#xe609;"})
}
}
Expand Down
44 changes: 44 additions & 0 deletions web/src/pages/home/components/SidebarItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<template>
<div>
<el-menu-item
v-if="!item.children"
:index="item.url"
:disabled="isDisabled"
>
<i :class="item.icon"></i>&nbsp;{{ item.name }}

</el-menu-item>
<el-submenu
v-else
:index="item.url"
>
<template slot="title">
<i :class="item.icon"></i>&nbsp;{{ item.name }}
</template>
<sidebar-item
v-for="child in item.children"
:key="child.url"
:item="child"
/>
</el-submenu>
</div>
</template>

<script>
export default {
name: 'SidebarItem',
props: ['item'],
computed: {
isDisabled() {
const routerName = this.$store.state.routerName;
// 适当调整路径逻辑以匹配你的需求
const pathCondition = this.$route.path === '/fastrunner/project_list';
// 根据你的全局状态或路由条件设置 disabled 状态
return routerName === 'ProjectList' || pathCondition;
}
},
components: {
SidebarItem: () => import('./SidebarItem') // 注意递归引用自身
}
};
</script>
Loading

0 comments on commit 9481ac6

Please sign in to comment.