houyaf 3 rokov pred
rodič
commit
dbd8b8d66f

+ 185 - 0
src/views/api/api/components/ApiList.vue

@@ -0,0 +1,185 @@
+<route lang="yaml">
+meta:
+  enabled: false
+</route>
+
+<script lang="ts" setup name="apiIndex">
+import { ElMessage } from 'element-plus'
+import PSApi from './Api.vue'
+import { getApiByList, updateApiStatus } from '@/api/api/apiApi'
+import useSettingsStore from '@/store/modules/settings'
+import { httpMethod } from '@/utils/tool'
+
+const settingsStore = useSettingsStore()
+const router = useRouter()
+const tabbar = useTabbar()
+
+interface Api {
+  bizId: number
+  objectId: number
+  oamId: number
+  apiId: number
+  apiMethod: number
+  apiType: number
+  apiTitle: string
+  apiCode: string
+  apiDesc: string
+  apiParams: string
+  status: number
+}
+
+const state = reactive({
+  dialogState: 1,
+  loading: false,
+  keywords: '',
+  apiList: [] as Api[],
+  search: {
+    keywords: '',
+    bizId: 0,
+    objectId: 0,
+  },
+})
+
+const leftTreeRef = ref()
+const getData = async () => {
+  const { bizId, objectId } = state.search
+  if (bizId > 0 && objectId > 0) {
+    state.loading = true
+    const { data } = await getApiByList({ bizId, objectId })
+    state.apiList = data
+    state.loading = false
+  }
+}
+
+onMounted(() => {
+  getData()
+})
+
+const apiRef = ref()
+const apiTableRef = ref()
+
+// 检索对象
+const onSearch = () => {
+  getData()
+}
+
+// 编辑API
+const onApiEdit = (data: { apiId: number }) => {
+  const apiId = data.apiId
+  apiRef.value.showEditApi(apiId)
+}
+
+// 编辑对象
+const onApiDebug = (row: { apiId: number }) => {
+  if (settingsStore.settings.tabbar.enable && settingsStore.settings.tabbar.mergeTabsBy !== 'activeMenu') {
+    tabbar.open({
+      name: 'apiDebug',
+      params: {
+        apiId: row.apiId,
+      },
+    })
+  }
+  else {
+    router.push({
+      name: 'apiDebug',
+      params: {
+        apiId: row.apiId,
+      },
+    })
+  }
+}
+
+async function onChangeStatus(row: { apiId: number; status: number }) {
+  const { msg } = await updateApiStatus(row.apiId, row.status)
+  ElMessage.success(msg)
+}
+
+defineExpose({
+  loadData(bizId: number, objectId: number) {
+    state.search.bizId = bizId
+    state.search.objectId = objectId
+    getData()
+  },
+})
+</script>
+
+<template>
+  <div class="container">
+    <tool-bar>
+      <template #right>
+        <el-input v-model="state.search.keywords" placeholder="请输入关键字" style="padding-right: 10px;" clearable />
+        <el-button type="primary" @click="onSearch">
+          <template #icon>
+            <el-icon>
+              <svg-icon name="i-ep:search" />
+            </el-icon>
+          </template>
+        </el-button>
+      </template>
+    </tool-bar>
+
+    <el-table ref="apiTableRef" v-loading="state.loading" class="list-table" :data="state.apiList" size="small" border stripe highlight-current-row height="100%">
+      <el-table-column type="index" label="序号" header-align="center" align="center" width="70" />
+
+      <el-table-column prop="apiTitle" label="名称" header-align="center" align="center" width="150">
+        <template #default="scope">
+          <span> {{ scope.row.apiTitle }} </span>
+        </template>
+      </el-table-column>
+
+      <el-table-column prop="apiMethod" label="请求" header-align="center" align="center" width="100">
+        <template #default="scope">
+          <el-tag type="warning">
+            {{ httpMethod(scope.row.apiMethod) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+
+      <el-table-column prop="apiCode" label="url" header-align="center" align="left" width="200">
+        <template #default="scope">
+          <el-tag type="success">
+            /{{ scope.row.objectCode }}/{{ scope.row.oamCode }}
+          </el-tag>
+        </template>
+      </el-table-column>
+
+      <el-table-column prop="apiDesc" label="说明" header-align="left" align="left">
+        <template #default="scope">
+          <span> {{ scope.row.apiDesc }} </span>
+        </template>
+      </el-table-column>
+
+      <el-table-column prop="status" label="状态" header-align="center" align="center" width="100">
+        <template #default="scope">
+          <el-switch
+            v-model="scope.row.status"
+            :active-value="1"
+            :inactive-value="0"
+            :loading="scope.row.loading"
+            inline-prompt
+            active-text="启用"
+            inactive-text="禁用"
+            @change="(status) => onChangeStatus(scope.row)"
+          />
+        </template>
+      </el-table-column>
+
+      <el-table-column label="操作" header-align="center" align="center" width="120">
+        <template #default="scope">
+          <el-button type="primary" size="small" plain @click="onApiDebug(scope.row)">
+            在线调试
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <PSApi ref="apiRef" @success="getData" />
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.container {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+}
+</style>

+ 20 - 299
src/views/api/api/index.vue

@@ -3,324 +3,45 @@ meta:
   enabled: false
 </route>
 
-<script lang="ts" setup name="apiIndex">
-import { ElMessage } from 'element-plus'
-import PSApi from './components/Api.vue'
-import { getBizData } from '@/api/biz/bizApi'
-import { getApiByList, updateApiStatus } from '@/api/api/apiApi'
-import useSettingsStore from '@/store/modules/settings'
-import { httpMethod } from '@/utils/tool'
+<script lang="ts" setup>
+import LeftBizObjectTreeComponent from '../components/BizObjectTree.vue'
+import ApiListComponent from './components/ApiList.vue'
+const bizObjectTreeRef = ref()
+const apiListRef = ref()
 
-const settingsStore = useSettingsStore()
-const router = useRouter()
-const tabbar = useTabbar()
-
-interface TreeNode {
-  label: string
-  isLeaf: boolean
-  value: number
-  bizId: number
-  objectId: number
-  children?: TreeNode[]
-}
-
-interface Api {
-  bizId: number
-  objectId: number
-  oamId: number
-  apiId: number
-  apiMethod: number
-  apiType: number
-  apiTitle: string
-  apiCode: string
-  apiDesc: string
-  apiParams: string
-  status: number
-}
-
-const state = reactive({
-  loading: false,
-  keywords: '',
-  treeData: [] as TreeNode[],
-  curBizId: 0,
-  curObjectId: 0,
-  apiList: [] as Api[],
-  dialogState: 1,
-  search: {
-    keywords: '',
-  },
-})
-
-const leftTreeRef = ref()
-const getApiData = async () => {
-  const curBizId = state.curBizId
-  const curObjectId = state.curObjectId
-  if (curBizId > 0 && curObjectId > 0) {
-    state.loading = true
-    const { data } = await getApiByList({ bizId: curBizId, objectId: curObjectId })
-    state.apiList = data
-    state.loading = false
-  }
-}
-
-const getData = async () => {
-  const { data } = await getBizData()
-  if (data && data.length > 0) {
-    data.forEach((biz: { label: string; bizTitle: string; children: any; isLeaf: boolean }) => {
-      biz.label = biz.bizTitle
-      biz.isLeaf = false
-      const objects = biz.children
-      objects.forEach((object: { label: string; objectTitle: string; isLeaf: boolean }) => {
-        object.label = object.objectTitle
-        object.isLeaf = true
-      })
-      biz.children = objects
-    })
-    state.treeData = data
-    state.curBizId = data[0].bizId
-    const objectList = data[0].children
-    if (objectList && objectList.length > 0) {
-      const obj = objectList[0]
-      state.curObjectId = obj.objectId
-      await getApiData()
-      await nextTick(() => {
-        leftTreeRef.value.setCurrentKey(obj.objectId)
-      })
-    }
-  }
-}
-
-onMounted(() => {
-  getData()
-})
-
-// 模块选择
-const onTreeNodeClick = (node: TreeNode) => {
-  if (node.isLeaf) {
-    state.curObjectId = node.objectId
-    getApiData()
-  }
-}
-
-const apiRef = ref()
-const apiTableRef = ref()
-
-// 检索对象
-const onSearch = () => {
-  getApiData()
-}
-
-// 编辑API
-const onApiEdit = (data: { apiId: number }) => {
-  const apiId = data.apiId
-  apiRef.value.showEditApi(apiId)
-}
-
-// 编辑对象
-const onApiDebug = (row: { apiId: number }) => {
-  if (settingsStore.settings.tabbar.enable && settingsStore.settings.tabbar.mergeTabsBy !== 'activeMenu') {
-    tabbar.open({
-      name: 'apiDebug',
-      params: {
-        apiId: row.apiId,
-      },
-    })
-  }
-  else {
-    router.push({
-      name: 'apiDebug',
-      params: {
-        apiId: row.apiId,
-      },
-    })
-  }
-}
-
-async function onChangeStatus(row: { apiId: number; status: number }) {
-  const { msg } = await updateApiStatus(row.apiId, row.status)
-  ElMessage.success(msg)
+const onItemSelect = (bizId: number, objectId: number) => {
+  apiListRef.value.loadData(bizId, objectId)
 }
 </script>
 
 <template>
   <div class="absolute-container">
-    <tool-header title="API管理">
-      <template #right />
-    </tool-header>
+    <tool-header title="事务模型" />
 
     <div class="page-main">
       <LayoutContainer left-side-width="250px" hide-left-side-toggle>
         <template #leftSide>
-          <el-scrollbar class="tree">
-            <ElTree ref="leftTreeRef" :data="state.treeData" default-expand-all node-key="moduleId" @node-click="onTreeNodeClick">
-              <template #default="{ node, data }">
-                <div class="custom-tree-node">
-                  <div class="label" :title="node.label">
-                    <el-icon size="16px" style="margin-right: 5px;">
-                      <svg-icon v-if="data.isLeaf" name="uim:box" />
-                      <svg-icon v-else name="bx:bxs-component" />
-                    </el-icon>
-                    <div class="text">
-                      {{ data.label }}
-                    </div>
-                  </div>
-                </div>
-              </template>
-            </ElTree>
-          </el-scrollbar>
+          <LeftBizObjectTreeComponent ref="bizObjectTreeRef" @onItemSelect="onItemSelect" />
         </template>
 
-        <div class="container">
-          <tool-bar>
-            <template #right>
-              <el-input v-model="state.search.keywords" placeholder="请输入关键字" style="padding-right: 10px;" clearable />
-              <el-button type="primary" @click="onSearch">
-                <template #icon>
-                  <el-icon>
-                    <svg-icon name="i-ep:search" />
-                  </el-icon>
-                </template>
-              </el-button>
-            </template>
-          </tool-bar>
-
-          <el-table ref="apiTableRef" v-loading="state.loading" class="list-table" :data="state.apiList" size="small" border stripe highlight-current-row height="100%">
-            <el-table-column type="index" label="序号" header-align="center" align="center" width="70" />
-
-            <el-table-column prop="apiTitle" label="名称" header-align="center" align="center" width="150">
-              <template #default="scope">
-                <span> {{ scope.row.apiTitle }} </span>
-              </template>
-            </el-table-column>
-
-            <el-table-column prop="apiMethod" label="请求" header-align="center" align="center" width="100">
-              <template #default="scope">
-                <el-tag type="warning">
-                  {{ httpMethod(scope.row.apiMethod) }}
-                </el-tag>
-              </template>
-            </el-table-column>
-
-            <el-table-column prop="apiCode" label="url" header-align="center" align="left" width="200">
-              <template #default="scope">
-                <el-tag type="success">
-                  /{{ scope.row.objectCode }}/{{ scope.row.oamCode }}
-                </el-tag>
-              </template>
-            </el-table-column>
-
-            <el-table-column prop="apiDesc" label="说明" header-align="left" align="left">
-              <template #default="scope">
-                <span> {{ scope.row.apiDesc }} </span>
-              </template>
-            </el-table-column>
-
-            <el-table-column prop="status" label="状态" header-align="center" align="center" width="100">
-              <template #default="scope">
-                <el-switch
-                  v-model="scope.row.status"
-                  :active-value="1"
-                  :inactive-value="0"
-                  :loading="scope.row.loading"
-                  inline-prompt
-                  active-text="启用"
-                  inactive-text="禁用"
-                  @change="(status) => onChangeStatus(scope.row)"
-                />
-              </template>
-            </el-table-column>
-
-            <el-table-column label="操作" header-align="center" align="center" width="120">
-              <template #default="scope">
-                <el-button type="primary" size="small" plain @click="onApiDebug(scope.row)">
-                  在线调试
-                </el-button>
-              </template>
-            </el-table-column>
-          </el-table>
-        </div>
+        <ApiListComponent ref="apiListRef" />
       </LayoutContainer>
     </div>
-    <PSApi ref="apiRef" @success="getApiData" />
   </div>
 </template>
 
 <style lang="scss" scoped>
-  .container {
-    height: 100%;
+.container {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+}
+
+.absolute-container {
+  :deep(.left-side) {
     display: flex;
     flex-direction: column;
+    height: 100%;
   }
-
-  .absolute-container {
-    :deep(.left-side) {
-      display: flex;
-      flex-direction: column;
-      height: 100%;
-
-      .btns {
-        display: inline-flex;
-        width: 100%;
-        margin-bottom: var(--container-padding);
-
-        .add {
-          width: 100%;
-        }
-      }
-
-      .tree {
-        flex: 1;
-        overflow-y: auto;
-
-        .el-tree {
-          .el-tree-node__content {
-            height: 40px;
-          }
-
-          .is-current > .el-tree-node__content {
-            background-color: var(--el-color-primary-light-9);
-          }
-
-          .custom-tree-node {
-            flex: 1;
-            position: relative;
-            width: 0;
-            height: 100%;
-            display: flex;
-            flex-direction: column;
-            justify-content: center;
-
-            .label {
-              display: inline-flex;
-              align-items: center;
-              width: calc(100% - 10px);
-              color: var(--el-text-color-primary);
-
-              .text {
-                @include text-overflow;
-              }
-            }
-
-            &:hover {
-              .actions {
-                display: block;
-              }
-            }
-
-            .actions {
-              display: none;
-              position: absolute;
-              right: 10px;
-              top: 50%;
-              transform: translateY(-50%);
-
-              .el-button {
-                padding: 5px 8px;
-              }
-            }
-          }
-        }
-      }
-    }
-  }
+}
 </style>

+ 157 - 0
src/views/api/components/BizObjectTree.vue

@@ -0,0 +1,157 @@
+<route lang="yaml">
+meta:
+  enabled: false
+</route>
+
+<script lang="ts" setup name="apiIndex">
+import { getBizData } from '@/api/biz/bizApi'
+const emit = defineEmits(['onItemSelect'])
+
+interface TreeNode {
+  label: string
+  isLeaf: boolean
+  value: number
+  bizId: number
+  objectId: number
+  children?: TreeNode[]
+}
+
+const state = reactive({
+  loading: false,
+  keywords: '',
+  treeData: [] as TreeNode[],
+  curBizId: 0,
+  curObjectId: 0,
+  dialogState: 1,
+  search: {
+    keywords: '',
+  },
+})
+
+const leftTreeRef = ref()
+const getData = async () => {
+  const { data } = await getBizData()
+  if (data && data.length > 0) {
+    data.forEach((biz: { label: string; bizTitle: string; children: any; isLeaf: boolean }) => {
+      biz.label = biz.bizTitle
+      biz.isLeaf = false
+      const objects = biz.children
+      objects.forEach((object: { label: string; objectTitle: string; isLeaf: boolean }) => {
+        object.label = object.objectTitle
+        object.isLeaf = true
+      })
+      biz.children = objects
+    })
+    state.treeData = data
+    state.curBizId = data[0].bizId
+    const objectList = data[0].children
+    if (objectList && objectList.length > 0) {
+      const obj = objectList[0]
+      state.curObjectId = obj.objectId
+      await nextTick(() => {
+        leftTreeRef.value.setCurrentKey(obj.objectId)
+        emit('onItemSelect', state.curBizId, state.curObjectId)
+      })
+    }
+  }
+}
+
+onMounted(() => {
+  getData()
+})
+
+// 模块选择
+const onTreeNodeClick = (node: TreeNode) => {
+  if (node.isLeaf) {
+    state.curBizId = node.bizId
+    state.curObjectId = node.objectId
+    emit('onItemSelect', state.curBizId, state.curObjectId)
+  }
+}
+</script>
+
+<template>
+  <el-scrollbar class="tree">
+    <ElTree ref="leftTreeRef" :data="state.treeData" default-expand-all node-key="moduleId" @node-click="onTreeNodeClick">
+      <template #default="{ node, data }">
+        <div class="custom-tree-node">
+          <div class="label" :title="node.label">
+            <el-icon size="16px" style="margin-right: 5px;">
+              <svg-icon v-if="data.isLeaf" name="uim:box" />
+              <svg-icon v-else name="bx:bxs-component" />
+            </el-icon>
+            <div class="text">
+              {{ data.label }}
+            </div>
+          </div>
+        </div>
+      </template>
+    </ElTree>
+  </el-scrollbar>
+</template>
+
+<style lang="scss" scoped>
+.btns {
+  display: inline-flex;
+  width: 100%;
+  margin-bottom: var(--container-padding);
+
+  .add {
+    width: 100%;
+  }
+}
+
+.tree {
+  flex: 1;
+  overflow-y: auto;
+
+  :deep(.el-tree) {
+    .el-tree-node__content {
+      height: 40px;
+    }
+
+    .is-current > .el-tree-node__content {
+      background-color: var(--el-color-primary-light-9);
+    }
+
+    .custom-tree-node {
+      flex: 1;
+      position: relative;
+      width: 0;
+      height: 100%;
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+
+      .label {
+        display: inline-flex;
+        align-items: center;
+        width: calc(100% - 10px);
+        color: var(--el-text-color-primary);
+
+        .text {
+          @include text-overflow;
+        }
+      }
+
+      &:hover {
+        .actions {
+          display: block;
+        }
+      }
+
+      .actions {
+        display: none;
+        position: absolute;
+        right: 10px;
+        top: 50%;
+        transform: translateY(-50%);
+
+        .el-button {
+          padding: 5px 8px;
+        }
+      }
+    }
+  }
+}
+</style>

+ 132 - 0
src/views/api/log/components/ApiLogList.vue

@@ -0,0 +1,132 @@
+<script lang="ts" setup name="apiLog">
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { deleteApiLogById, getApiLogByPage } from '@/api/api/apiLogApi'
+const { pagination, onSizeChange, onCurrentChange } = usePagination()
+
+interface ApiLog {
+  bizId: number
+  objectId: number
+  oamId: number
+  apiId: number
+  apiMethod: number
+  apiType: number
+  apiTitle: string
+  apiCode: string
+  apiDesc: string
+  apiParams: string
+  status: number
+}
+
+const state = reactive({
+  loading: false,
+  keywords: '',
+  logList: [] as ApiLog[],
+  dialogState: 1,
+  search: {
+    bizId: 0,
+    objectId: 0,
+    keywords: '',
+  },
+})
+
+const getData = async () => {
+  const { bizId, objectId } = state.search
+  if (bizId > 0 && objectId > 0) {
+    state.loading = true
+    const { data } = await getApiLogByPage(state.search)
+    state.logList = data
+    state.loading = false
+  }
+}
+
+// 每页数量切换
+function sizeChange(size: number) {
+  onSizeChange(size).then(() => getData())
+}
+
+// 当前页码切换(翻页)
+function currentChange(page = 1) {
+  onCurrentChange(page).then(() => getData())
+}
+// 查询
+const onSearch = () => {
+  getData()
+}
+
+onMounted(() => {
+  getData()
+})
+
+// 删除日志
+const onReqDel = async (data: { apiTitle: any; reqId: number }) => {
+  ElMessageBox.confirm('确认删除吗?', '确认信息').then(async () => {
+    const { msg } = await deleteApiLogById(data.reqId)
+    ElMessage.success(msg)
+    await getData()
+  })
+}
+
+defineExpose({
+  loadData(bizId: number, objectId: number) {
+    state.search.bizId = bizId
+    state.search.objectId = objectId
+    getData()
+  },
+})
+</script>
+
+<template>
+  <div class="container">
+    <tool-bar>
+      <template #right>
+        <el-input v-model="state.search.keywords" placeholder="请输入名称,支持模糊查询" style="padding-right: 10px;" clearable />
+        <el-button type="primary" @click="onSearch">
+          <template #icon>
+            <el-icon>
+              <svg-icon name="i-ep:search" />
+            </el-icon>
+          </template>
+        </el-button>
+      </template>
+    </tool-bar>
+
+    <el-table ref="apiReqTableRef" v-loading="state.loading" class="list-table" :data="state.logList" size="small" border stripe highlight-current-row>
+      <el-table-column type="index" align="center" label="序号" width="60" />
+
+      <el-table-column align="center" width="100" label="接口名称" prop="apiTitle">
+        <template #default="scope">
+          <span>{{ scope.row.apiTitle }}</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column align="center" label="调用者IP" prop="appTitle">
+        <template #default="scope">
+          <span>{{ scope.row.appTitle }}</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column align="center" label="创建时间" prop="reqTime">
+        <template #default="scope">
+          <span>{{ scope.row.reqTime }}</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="操作" header-align="center" align="center" width="220">
+        <template #default="scope">
+          <el-button v-if="scope.row.isFixed !== 1" size="small" type="danger" @click="onReqDel(scope.row)">
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <el-pagination :current-page="pagination.page" :total="pagination.total" :page-size="pagination.size" :page-sizes="pagination.sizes" :layout="pagination.layout" :hide-on-single-page="false" class="pagination" background @current-change="currentChange" @size-change="sizeChange" />
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.container {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+}
+</style>

+ 16 - 247
src/views/api/log/index.vue

@@ -1,196 +1,29 @@
-<script lang="ts" setup name="apiLog">
-import { ElMessage, ElMessageBox } from 'element-plus'
-import { deleteApiLogById, getApiLogByPage } from '@/api/api/apiLogApi'
-import { getBizData } from '@/api/biz/bizApi'
-const { pagination, onSizeChange, onCurrentChange } = usePagination()
-
-interface TreeNode {
-  label: string
-  isLeaf: boolean
-  value: number
-  bizId: number
-  objectId: number
-  children?: TreeNode[]
-}
-
-interface ApiLog {
-  bizId: number
-  objectId: number
-  oamId: number
-  apiId: number
-  apiMethod: number
-  apiType: number
-  apiTitle: string
-  apiCode: string
-  apiDesc: string
-  apiParams: string
-  status: number
-}
-
-const state = reactive({
-  loading: false,
-  keywords: '',
-  treeData: [] as TreeNode[],
-  curBizId: 0,
-  curObjectId: 0,
-  logList: [] as ApiLog[],
-  dialogState: 1,
-  search: {
-    bizId: 0,
-    objectId: 0,
-    keywords: '',
-  },
-})
-
-// 查询日志列表
-const leftTreeRef = ref()
-
-const getApiLogData = async () => {
-  const curBizId = state.curBizId
-  const curObjectId = state.curObjectId
-  if (curBizId > 0 && curObjectId > 0) {
-    state.loading = true
-    state.search.bizId = curBizId
-    state.search.objectId = curObjectId
-    const { data } = await getApiLogByPage(state.search)
-    state.logList = data
-    state.loading = false
-  }
-}
-
-const getData = async () => {
-  const { data } = await getBizData()
-  state.treeData = data
-
-  if (data && data.length > 0) {
-    state.curBizId = data[0].bizId
-
-    data.forEach((biz: { label: string; bizTitle: string; children: any; isLeaf: boolean }) => {
-      biz.label = biz.bizTitle
-      biz.isLeaf = false
-      const objects = biz.children
-      objects.forEach((object: { label: string; objectTitle: string; isLeaf: boolean }) => {
-        object.label = object.objectTitle
-        object.isLeaf = true
-      })
-      biz.children = objects
-    })
-
-    await getApiLogData()
-    await nextTick(() => {
-      leftTreeRef.value.setCurrentKey(data[0].bizId)
-    })
-  }
-}
-
-// 每页数量切换
-function sizeChange(size: number) {
-  onSizeChange(size).then(() => getApiLogData())
-}
-
-// 当前页码切换(翻页)
-function currentChange(page = 1) {
-  onCurrentChange(page).then(() => getApiLogData())
-}
-// 查询
-const onSearch = () => {
-  getApiLogData()
-}
-
-onMounted(() => {
-  getData()
-})
-
-// 模块选择
-const onTreeNodeClick = (node: TreeNode) => {
-  if (node.isLeaf) {
-    state.curBizId = node.bizId
-    state.curObjectId = node.objectId
-    getApiLogData()
-  }
-}
-
-// 删除日志
-const onReqDel = async (data: { apiTitle: any; reqId: number }) => {
-  ElMessageBox.confirm('确认删除吗?', '确认信息').then(async () => {
-    const { msg } = await deleteApiLogById(data.reqId)
-    ElMessage.success(msg)
-    await getApiLogData()
-  })
+<route lang="yaml">
+meta:
+  enabled: false
+</route>
+
+<script lang="ts" setup>
+import LeftBizObjectTreeComponent from '../components/BizObjectTree.vue'
+import ApiLogListComponent from './components/ApiLogList.vue'
+const bizObjectTreeRef = ref()
+const apiLogListRef = ref()
+const onItemSelect = (bizId: number, objectId: number) => {
+  apiLogListRef.value.loadData(bizId, objectId)
 }
 </script>
 
 <template>
   <div class="absolute-container">
-    <tool-header title="Api日志" />
+    <tool-header title="事务模型" />
+
     <div class="page-main">
       <LayoutContainer left-side-width="250px" hide-left-side-toggle>
         <template #leftSide>
-          <el-scrollbar class="tree">
-            <ElTree ref="leftTreeRef" :data="state.treeData" default-expand-all node-key="moduleId" @node-click="onTreeNodeClick">
-              <template #default="{ node, data }">
-                <div class="custom-tree-node">
-                  <div class="label" :title="node.label">
-                    <el-icon size="16px" style="margin-right: 5px;">
-                      <svg-icon v-if="data.isLeaf > 0" name="uim:box" />
-                      <svg-icon v-else name="bx:bxs-component" />
-                    </el-icon>
-                    <div class="text">
-                      {{ data.label }}
-                    </div>
-                  </div>
-                  <div v-if="data.isLeaf" class="actions" />
-                </div>
-              </template>
-            </ElTree>
-          </el-scrollbar>
+          <LeftBizObjectTreeComponent ref="bizObjectTreeRef" @onItemSelect="onItemSelect" />
         </template>
 
-        <div class="container">
-          <tool-bar>
-            <template #right>
-              <el-input v-model="state.search.keywords" placeholder="请输入名称,支持模糊查询" style="padding-right: 10px;" clearable />
-              <el-button type="primary" @click="onSearch">
-                <template #icon>
-                  <el-icon>
-                    <svg-icon name="i-ep:search" />
-                  </el-icon>
-                </template>
-              </el-button>
-            </template>
-          </tool-bar>
-
-          <el-table ref="apiReqTableRef" v-loading="state.loading" class="list-table" :data="state.logList" size="small" border stripe highlight-current-row>
-            <el-table-column type="index" align="center" label="序号" width="60" />
-
-            <el-table-column align="center" width="100" label="接口名称" prop="apiTitle">
-              <template #default="scope">
-                <span>{{ scope.row.apiTitle }}</span>
-              </template>
-            </el-table-column>
-
-            <el-table-column align="center" label="调用者IP" prop="appTitle">
-              <template #default="scope">
-                <span>{{ scope.row.appTitle }}</span>
-              </template>
-            </el-table-column>
-
-            <el-table-column align="center" label="创建时间" prop="reqTime">
-              <template #default="scope">
-                <span>{{ scope.row.reqTime }}</span>
-              </template>
-            </el-table-column>
-
-            <el-table-column label="操作" header-align="center" align="center" width="220">
-              <template #default="scope">
-                <el-button v-if="scope.row.isFixed !== 1" size="small" type="danger" @click="onReqDel(scope.row)">
-                  删除
-                </el-button>
-              </template>
-            </el-table-column>
-          </el-table>
-          <el-pagination :current-page="pagination.page" :total="pagination.total" :page-size="pagination.size" :page-sizes="pagination.sizes" :layout="pagination.layout" :hide-on-single-page="false" class="pagination" background @current-change="currentChange" @size-change="sizeChange" />
-        </div>
+        <ApiLogListComponent ref="apiLogListRef" />
       </LayoutContainer>
     </div>
   </div>
@@ -208,70 +41,6 @@ const onReqDel = async (data: { apiTitle: any; reqId: number }) => {
     display: flex;
     flex-direction: column;
     height: 100%;
-
-    .btns {
-      display: inline-flex;
-      width: 100%;
-      margin-bottom: var(--container-padding);
-
-      .add {
-        width: 100%;
-      }
-    }
-
-    .tree {
-      flex: 1;
-      overflow-y: auto;
-
-      .el-tree {
-        .el-tree-node__content {
-          height: 40px;
-        }
-
-        .is-current > .el-tree-node__content {
-          background-color: var(--el-color-primary-light-9);
-        }
-
-        .custom-tree-node {
-          flex: 1;
-          position: relative;
-          width: 0;
-          height: 100%;
-          display: flex;
-          flex-direction: column;
-          justify-content: center;
-
-          .label {
-            display: inline-flex;
-            align-items: center;
-            width: calc(100% - 10px);
-            color: var(--el-text-color-primary);
-
-            .text {
-              @include text-overflow;
-            }
-          }
-
-          &:hover {
-            .actions {
-              display: block;
-            }
-          }
-
-          .actions {
-            display: none;
-            position: absolute;
-            right: 10px;
-            top: 50%;
-            transform: translateY(-50%);
-
-            .el-button {
-              padding: 5px 8px;
-            }
-          }
-        }
-      }
-    }
   }
 }
 </style>