houyaf 3 лет назад
Родитель
Сommit
8e62213952

+ 16 - 4
src/router/modules/api.ts

@@ -15,7 +15,7 @@ const routes: RouteRecordRaw[] = [
     children: [
       {
         path: 'index',
-        name: 'api_index',
+        name: 'apiIndex',
         component: () => import('@/views/api/api/index.vue'),
         meta: {
           title: 'API接口',
@@ -24,13 +24,25 @@ const routes: RouteRecordRaw[] = [
           activeMenu: '/api',
         },
       },
+      {
+        path: 'trans/:moduleId/:apiId',
+        name: 'apiTrans',
+        component: () => import('@/views/api/trans/index.vue'),
+        meta: {
+          title: 'Api事务',
+          sidebar: false,
+          activeMenu: '/api',
+          cache: true,
+          noCache: 'apiTrans',
+        },
+      },
     ],
   },
   {
     path: '/api/log',
     component: Layout,
     redirect: '/api/log/index',
-    name: 'api_log',
+    name: 'apiLog',
     meta: {
       title: 'API日志',
       icon: 'ep:hot-water',
@@ -38,10 +50,10 @@ const routes: RouteRecordRaw[] = [
     children: [
       {
         path: 'index',
-        name: 'api_log_index',
+        name: 'apiLogIndex',
         component: () => import('@/views/api/log/index.vue'),
         meta: {
-          title: '调用日志',
+          title: 'API日志',
           sidebar: false,
           breadcrumb: false,
           activeMenu: '/api/log',

+ 2 - 2
src/views/api/api/index.vue

@@ -99,7 +99,7 @@ const onModuleEdit = (data: { moduleId: number }) => {
 
 // 模块删除
 const onModuleDelete = (data: any) => {
-  ElMessageBox.confirm(`确认删除「${data.modTitle}」吗?`, '确认信息').then(async () => {
+  ElMessageBox.confirm(`确认删除「${data.moduleTitle}」吗?`, '确认信息').then(async () => {
     await deleteModuleById(data.moduleId)
     await getModuleData()
     ElMessage.success({
@@ -121,8 +121,8 @@ const onTreeNodeClick = (node: TreeNode) => {
   }
 }
 
-const apiTableRef = ref()
 const apiRef = ref()
+const apiTableRef = ref()
 
 // 检索对象
 const onSearch = () => {

+ 280 - 0
src/views/api/trans/components/ApiTrans.vue

@@ -0,0 +1,280 @@
+<router lang="yaml">
+meta:
+  enabled: false
+</router>
+
+<script lang="ts" setup name="apiTrans">
+import type { FormInstance } from 'element-plus'
+import { ElMessage } from 'element-plus'
+
+import ObjectSelector from './ObjectOAMSelector.vue'
+import useSettingsStore from '@/store/modules/settings'
+import { getApiById } from '@/api/api/apiApi'
+import { createX, deleteX, getX, patchX, updateX } from '@/api/api/apiGatewayApi'
+
+const settingsStore = useSettingsStore()
+const route = useRoute()
+const router = useRouter()
+const tabbar = useTabbar()
+
+const moduleId = parseInt(route.params.moduleId.toString())
+const apiId = parseInt(route.params.apiId.toString())
+
+const state = reactive({
+  loading: false,
+  apiTitle: '',
+  apiCode: '',
+  apiType: 0,
+  keywords: '',
+  atuList: [],
+  dialogState: 1,
+  search: {
+    moduleId,
+    apiId,
+    keywords: '',
+  },
+  params: '',
+  result: '',
+})
+
+const ObjectSelectorRef = ref()
+
+// 查询数据
+const getData = async () => {
+  state.loading = true
+  const { data } = await getApiById(moduleId, apiId)
+  state.apiTitle = data.apiTitle
+  state.apiCode = data.apiCode
+  state.apiType = data.apiType
+}
+
+onMounted(() => {
+  getData()
+})
+
+const formRef = ref<FormInstance>()
+
+const onAdd = () => {
+  ObjectSelectorRef.value.showModel(moduleId, apiId)
+}
+
+const onGenerateParams = async () => {
+  // const { data } = await generateParamsByCode(state.apiCode)
+  // state.params = JSON.stringify(data)
+}
+
+const onExecute = async () => {
+  try {
+    const apiType = state.apiType
+    const apiCode = state.apiCode
+    const params = JSON.parse(state.params)
+    if (apiType === 1) {
+      const { data } = await getX(apiCode, params)
+      state.result = JSON.stringify(data)
+    }
+    else if (apiType === 2) {
+      const { data } = await createX(apiCode, params)
+      state.result = JSON.stringify(data)
+    }
+    else if (apiType === 3) {
+      const { data } = await updateX(apiCode, params)
+      state.result = JSON.stringify(data)
+    }
+    else if (apiType === 4) {
+      const { data } = await patchX(apiCode, params)
+      state.result = JSON.stringify(data)
+    }
+    else if (apiType === 5) {
+      const { data } = await deleteX(apiCode, params)
+      state.result = JSON.stringify(data)
+    }
+  }
+  catch (err) {
+    ElMessage.error('提交失败')
+  }
+}
+// 选择对象模型回调
+const onObjectSelSuccess = () => {
+  getData()
+}
+
+// 返回列表页
+function goBack() {
+  if (settingsStore.settings.tabbar.enable && settingsStore.settings.tabbar.mergeTabsBy !== 'activeMenu') {
+    tabbar.close({ name: 'api' })
+  }
+  else {
+    router.push({ name: 'api' })
+  }
+}
+</script>
+
+<template>
+  <div class="absolute-container">
+    <page-header :title="state.apiTitle" :content="state.apiCode">
+      <el-button size="default" round @click="goBack">
+        <template #icon>
+          <el-icon>
+            <svg-icon name="i-ep:arrow-left" />
+          </el-icon>
+        </template>
+        返回
+      </el-button>
+    </page-header>
+    <div class="page-main">
+      <LayoutContainer left-side-width="300px" hide-left-side-toggle>
+        <template #leftSide>
+          <el-space wrap>
+            <el-button type="primary" size="default" @click="onAdd">
+              <template #icon>
+                <el-icon>
+                  <svg-icon name="i-ep:plus" />
+                </el-icon>
+              </template>
+            </el-button>
+          </el-space>
+
+          <el-table v-loading="state.loading" class="list-table" :data="state.atuList" border stripe highlight-current-row height="100%">
+            <el-table-column prop="bizTitle" label="模型" header-align="center" align="center" min-width="150px" />
+
+            <el-table-column prop="objectTitle" label="对象" header-align="center" align="center" min-width="150px" />
+
+            <el-table-column prop="oamTitle" label="行为" header-align="center" align="center" />
+          </el-table>
+        </template>
+
+        <div class="form">
+          <tool-header>
+            <template #right>
+              <el-button type="primary" @click="onGenerateParams">
+                生成参数
+              </el-button>
+            </template>
+          </tool-header>
+          <el-form ref="formRef" label-width="100px" label-position="top">
+            <el-form-item label="数据参数" prop="code">
+              <el-input v-model="state.params" type="textarea" rows="10" placeholder="数据" />
+            </el-form-item>
+            <el-form-item v-if="state.result" label="生成参数" prop="code">
+              <el-input v-model="state.result" type="textarea" rows="10" placeholder="数据" readonly />
+            </el-form-item>
+            <div class="action-bottom">
+              <el-button type="primary" @click="onExecute">
+                立即执行
+              </el-button>
+            </div>
+          </el-form>
+          <ObjectSelector ref="ObjectSelectorRef" @on-success="onObjectSelSuccess" />
+        </div>
+      </LayoutContainer>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.absolute-container {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+
+  .page-header {
+    margin-bottom: 0;
+  }
+
+  .page-main {
+    flex: 1;
+    overflow: auto;
+    display: flex;
+    flex-direction: column;
+
+    .flex-container {
+      position: static;
+
+      :deep(.left-side) {
+        overflow: auto;
+        display: flex;
+        flex-direction: column;
+      }
+
+      :deep(.main-container) {
+        height: 100%;
+        display: flex;
+        flex-direction: column;
+
+        .empty {
+          flex: 1;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          font-size: 32px;
+          color: var(--el-text-color-placeholder);
+        }
+      }
+    }
+
+    .form {
+      flex: 1;
+      min-height: 0;
+      display: flex;
+      flex-direction: column;
+
+      .el-form {
+        flex: 1;
+        min-height: 0;
+        display: flex;
+        flex-direction: column;
+
+        .columns-table {
+          flex: 1;
+          height: 0;
+          display: flex;
+          flex-direction: column;
+
+          :deep(.el-form-item__content) {
+            min-height: 0;
+
+            .el-table {
+              height: 100%;
+            }
+          }
+        }
+      }
+
+      .action-bottom {
+        padding-top: 2px;
+        text-align: center;
+      }
+
+      .el-table {
+        .el-table__row {
+          .index {
+            display: inline-block;
+          }
+
+          .delete {
+            display: none;
+          }
+
+          &:hover {
+            .index {
+              display: none;
+            }
+
+            .delete {
+              display: inline-block;
+            }
+          }
+
+          .el-tag.sortable,
+          .el-tag.sortable .el-icon {
+            cursor: s-resize;
+          }
+        }
+      }
+    }
+
+  }
+}
+</style>

+ 292 - 0
src/views/api/trans/components/ObjectOAMSelector.vue

@@ -0,0 +1,292 @@
+<route lang="yaml">
+meta:
+  enabled: false
+</route>
+
+<script lang="ts" setup>
+import { getBizByList } from '@/api/biz/bizApi'
+import { getObjectByList } from '@/api/biz/bizObjectApi'
+import { getObjectOAMByList } from '@/api/biz/bizObjectOAMApi'
+import { updateApi } from '@/api/api/apiApi'
+
+interface TreeNode {
+  label: string
+  isLeaf: boolean
+  bizId: number
+  children?: TreeNode[]
+}
+
+interface Object {
+  bizId: number
+  objectId: number
+  objectTitle: string
+  objectCode: string
+  comment: string
+}
+
+const emit = defineEmits(['onSuccess'])
+
+const state = reactive({
+  loading: false,
+  keywords: '',
+  title: '',
+  treeData: [] as TreeNode[],
+  curBizId: 0,
+  curObjectId: 0,
+  objectList: [] as Object[],
+  objectOAMList: [] as Object[],
+  dialogState: 1,
+  search: {
+    apiId: 0,
+    keywords: '',
+  },
+  formData: {
+    moduleId: 0,
+    apiId: 0,
+    bizId: 0,
+    objectId: 0,
+    oamId: 1,
+  },
+  objectOAMDetail: {},
+})
+
+const leftTreeRef = ref()
+const getObjectOAMData = async () => {
+  const curBizId = state.curBizId
+  const curObjectId = state.curObjectId
+  if (curBizId > 0 && curObjectId > 0) {
+    state.loading = true
+    const { data } = await getObjectOAMByList({ bizId: curBizId })
+    state.objectOAMList = data
+    state.loading = false
+  }
+}
+
+const getObjectData = async () => {
+  const curBizId = state.curBizId
+  if (curBizId > 0) {
+    state.loading = true
+    const { data } = await getObjectByList({ bizId: curBizId })
+    state.objectList = data
+    state.loading = false
+  }
+}
+
+const getBizData = async () => {
+  const { data } = await getBizByList('')
+  const children: TreeNode[] = []
+  data.forEach((item: any) => {
+    return children.push({
+      label: item.bizTitle,
+      bizId: item.bizId,
+      isLeaf: true,
+    })
+  })
+  state.treeData = [
+    {
+      label: '模型库',
+      isLeaf: false,
+      bizId: -1,
+      children,
+    },
+  ]
+
+  if (data && data.length > 0) {
+    state.curBizId = data[0].bizId
+    // nextTick(() => {
+    //   leftTreeRef.value.setCurrentKey(data[0].modelId)
+    // })
+    await getObjectData()
+  }
+}
+
+onMounted(() => {
+  getBizData()
+})
+
+// 模型选择
+const onTreeNodeClick = (node: TreeNode) => {
+  if (node.isLeaf) {
+    state.curBizId = node.bizId
+    getObjectData()
+  }
+}
+
+const objectTableRef = ref()
+const dialogVisible = ref(false)
+const onObjectSel = async (row: { objectId: number }) => {
+  state.curObjectId = row.objectId
+  await getObjectOAMData()
+}
+
+const objectOAMTableRef = ref()
+const onObjectOAMSel = async (row: { bizId: number; objectId: number; oamId: number }) => {
+  state.formData.bizId = row.bizId
+  state.formData.objectId = row.objectId
+  state.formData.oamId = row.oamId
+  state.objectOAMDetail = row
+}
+
+const onSave = async () => {
+  await updateApi(state.formData)
+  emit('onSuccess')
+  dialogVisible.value = false
+}
+
+const onCancel = () => {
+  dialogVisible.value = false
+}
+
+// 点击选择
+defineExpose({
+  showModel(moduleId: number, apiId: number) {
+    state.search.apiId = apiId
+    state.formData.moduleId = moduleId
+    state.formData.apiId = apiId
+    dialogVisible.value = true
+  },
+})
+</script>
+
+<template>
+  <el-drawer v-model="dialogVisible" :title="state.title" size="100%">
+    <el-row :gutter="10" style="height:100%">
+      <el-col :xs="24" :span="5" class="small-row">
+        <el-card style="height:100%">
+          <el-scrollbar class="tree">
+            <ElTree ref="leftTreeRef" :data="state.treeData" default-expand-all node-key="bizId" @node-click="onTreeNodeClick">
+              <template #default="{ node, data }">
+                <div class="custom-tree-node">
+                  <div class="label" :title="node.label">
+                    <el-icon v-if="data.isLeaf" size="16px" style="margin-right: 5px;">
+                      <svg-icon name="uim:box" />
+                    </el-icon>
+                    <div class="text">
+                      {{ data.label }}
+                    </div>
+                  </div>
+                </div>
+              </template>
+            </ElTree>
+          </el-scrollbar>
+        </el-card>
+      </el-col>
+
+      <el-col :xs="24" :span="5" class="objectListtable lg-row">
+        <el-card style="height:100%">
+          <el-table
+            v-if="state.objectList && state.objectList.length > 0"
+            ref="objectTableRef"
+            v-loading="state.loading"
+            class="list-table"
+            :data="state.objectList" border :show-header="false"
+            stripe highlight-current-row height="100%" @row-click="onObjectSel"
+          >
+            <el-table-column prop="objectTitle" label="名称" header-align="center" align="center" minwidth="200" />
+            <el-table-column prop="objectCode" label="代码" header-align="center" align="center" minwidth="150" />
+            <el-table-column prop="objectType" label="类型" header-align="center" align="center" minwidth="150">
+              <template #default="scope">
+                <span v-if="scope.row.objectType === 1">实体对象</span>
+                <span v-else>视图对象</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="comment" label="说明" header-align="center" align="left" />
+          </el-table>
+          <el-Empty v-else />
+        </el-card>
+      </el-col>
+      <el-col :xs="24" :span="5" class="objectOAMTableRef small-row">
+        <el-card style="height:100%">
+          <el-table
+            v-if="state.objectOAMList && state.objectOAMList.length > 0"
+            ref="objectOAMTableRef"
+            v-loading="state.loading"
+            class="list-table"
+            :data="state.objectOAMList"
+            border :show-header="false"
+            stripe highlight-current-row height="100%" @row-click="onObjectOAMSel"
+          >
+            <el-table-column prop="oamTitle" label="名称" header-align="center" align="center" minwidth="200" />
+            <el-table-column prop="oamType" label="类型" header-align="center" align="center" minwidth="150" />
+            <el-table-column prop="oamDesc" label="说明" header-align="center" align="left" />
+          </el-table>
+          <el-Empty v-else />
+        </el-card>
+      </el-col>
+      <el-col :xs="24" :span="9" class="objectOAMTableRef">
+        <el-card style="height:100%">
+          <ul v-if="state.objectOAMDetail" class="result-container">
+            <li v-for="(value, key) in state.objectOAMDetail" :key="key">
+              <h3> {{ key }}</h3>
+              <p>{{ value }}</p>
+            </li>
+          </ul>
+          <el-Empty v-else />
+
+          <el-button type="success" @click="onSave">
+            保存
+          </el-button>
+          <el-button type="info" @click="onCancel">
+            取消
+          </el-button>
+        </el-card>
+      </el-col>
+    </el-row>
+  </el-drawer>
+</template>
+
+<style lang="scss" scoped>
+:deep(.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>

+ 281 - 0
src/views/api/trans/index.vue

@@ -0,0 +1,281 @@
+<route lang="yaml">
+meta:
+  enabled: false
+</route>
+
+<script lang="ts" setup name="PagesExampleTable">
+import type { FormInstance } from 'element-plus'
+import ObjectOAMSelector from './components/ApiTrans.vue'
+import useSettingsStore from '@/store/modules/settings'
+import { getApiById } from '@/api/api/apiApi'
+import { createX, deleteX, getX, patchX, updateX } from '@/api/api/apiGatewayApi'
+
+const settingsStore = useSettingsStore()
+const route = useRoute()
+const router = useRouter()
+const tabbar = useTabbar()
+
+const moduleId = parseInt(route.params.moduleId.toString())
+const apiId = parseInt(route.params.apiId.toString())
+
+const state = reactive({
+  loading: false,
+  apiTitle: '',
+  apiCode: '',
+  apiType: 0,
+  keywords: '',
+  atuList: [],
+  dialogState: 1,
+  search: {
+    moduleId,
+    apiId,
+    keywords: '',
+  },
+  params: '',
+  result: '',
+})
+
+const BizObjectSelectorRef = ref()
+
+// 查询数据
+const getData = async () => {
+  state.loading = true
+  const { data } = await getApiById(moduleId, apiId)
+  state.apiTitle = data.apiTitle
+  state.apiCode = data.apiCode
+  state.apiType = data.apiType
+}
+
+onMounted(() => {
+  getData()
+})
+
+const formRef = ref<FormInstance>()
+
+const onAdd = () => {
+  BizObjectSelectorRef.value.showModel(moduleId, apiId)
+}
+
+const onGenerateParams = async () => {
+  const { data } = await generateParamsByCode(state.apiCode)
+  state.params = JSON.stringify(data)
+}
+
+const onExecute = async () => {
+  try {
+    const apiType = state.apiType
+    const apiCode = state.apiCode
+    const params = JSON.parse(state.params)
+    if (apiType === 1) {
+      const { data } = await getX(apiCode, params)
+      state.result = JSON.stringify(data)
+    }
+    else if (apiType === 2) {
+      const { data } = await createX(apiCode, params)
+      state.result = JSON.stringify(data)
+    }
+    else if (apiType === 3) {
+      const { data } = await updateX(apiCode, params)
+      state.result = JSON.stringify(data)
+    }
+    else if (apiType === 4) {
+      const { data } = await patchX(apiCode, params)
+      state.result = JSON.stringify(data)
+    }
+    else if (apiType === 5) {
+      const { data } = await deleteX(apiCode, params)
+      state.result = JSON.stringify(data)
+    }
+  }
+  catch (err) {
+    ElMessage.error('提交失败')
+  }
+}
+// 选择对象模型回调
+const onObjectSelSuccess = () => {
+  getData()
+}
+
+// 返回列表页
+function goBack() {
+  if (settingsStore.settings.tabbar.enable && settingsStore.settings.tabbar.mergeTabsBy !== 'activeMenu') {
+    tabbar.close({ name: 'paas_api' })
+  }
+  else {
+    router.push({ name: 'paas_api' })
+  }
+}
+</script>
+
+<template>
+  <div class="absolute-container">
+    <page-header :title="state.apiTitle" :content="state.apiCode">
+      <el-button size="default" round @click="goBack">
+        <template #icon>
+          <el-icon>
+            <svg-icon name="i-ep:arrow-left" />
+          </el-icon>
+        </template>
+        返回
+      </el-button>
+    </page-header>
+    <div class="page-main">
+      <LayoutContainer left-side-width="650px" hide-left-side-toggle>
+        <template #leftSide>
+          <el-space wrap>
+            <el-button type="primary" size="default" @click="onAdd">
+              <template #icon>
+                <el-icon>
+                  <svg-icon name="i-ep:plus" />
+                </el-icon>
+              </template>
+            </el-button>
+          </el-space>
+
+          <el-table v-loading="state.loading" class="list-table" :data="state.atuList" border stripe highlight-current-row height="100%">
+            <el-table-column type="index" label="序号" header-align="center" align="center" width="70" />
+
+            <el-table-column prop="modelTitle" label="模型" header-align="center" align="center" min-width="150px" />
+
+            <el-table-column prop="objectTitle" label="对象" header-align="center" align="center" min-width="150px" />
+
+            <el-table-column prop="oamTitle" label="行为" header-align="center" align="center" />
+
+          </el-table>
+        </template>
+
+        <div class="form">
+          <tool-header>
+            <template #right>
+              <el-button type="primary" @click="onGenerateParams">
+                生成参数
+              </el-button>
+            </template>
+          </tool-header>
+          <el-form ref="formRef" label-width="100px" label-position="top">
+            <el-form-item label="数据参数" prop="code">
+              <el-input v-model="state.params" type="textarea" rows="10" placeholder="数据" />
+            </el-form-item>
+            <el-form-item v-if="state.result" label="生成参数" prop="code">
+              <el-input v-model="state.result" type="textarea" rows="10" placeholder="数据" readonly />
+            </el-form-item>
+            <div class="action-bottom">
+              <el-button type="primary" @click="onExecute">
+                立即执行
+              </el-button>
+            </div>
+          </el-form>
+          <ModelObjectSelector ref="ModelObjectSelectorRef" @on-success="onObjectSelSuccess" />
+        </div>
+      </LayoutContainer>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.absolute-container {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+
+  .page-header {
+    margin-bottom: 0;
+  }
+
+  .page-main {
+    flex: 1;
+    overflow: auto;
+    display: flex;
+    flex-direction: column;
+
+    .flex-container {
+      position: static;
+
+      :deep(.left-side) {
+        overflow: auto;
+        display: flex;
+        flex-direction: column;
+      }
+
+      :deep(.main-container) {
+        height: 100%;
+        display: flex;
+        flex-direction: column;
+
+        .empty {
+          flex: 1;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          font-size: 32px;
+          color: var(--el-text-color-placeholder);
+        }
+      }
+    }
+
+    .form {
+      flex: 1;
+      min-height: 0;
+      display: flex;
+      flex-direction: column;
+
+      .el-form {
+        flex: 1;
+        min-height: 0;
+        display: flex;
+        flex-direction: column;
+
+        .columns-table {
+          flex: 1;
+          height: 0;
+          display: flex;
+          flex-direction: column;
+
+          :deep(.el-form-item__content) {
+            min-height: 0;
+
+            .el-table {
+              height: 100%;
+            }
+          }
+        }
+      }
+
+      .action-bottom {
+        padding-top: 2px;
+        text-align: center;
+      }
+
+      .el-table {
+        .el-table__row {
+          .index {
+            display: inline-block;
+          }
+
+          .delete {
+            display: none;
+          }
+
+          &:hover {
+            .index {
+              display: none;
+            }
+
+            .delete {
+              display: inline-block;
+            }
+          }
+
+          .el-tag.sortable,
+          .el-tag.sortable .el-icon {
+            cursor: s-resize;
+          }
+        }
+      }
+    }
+
+  }
+}
+</style>

+ 0 - 0
src/views/guide/index.vue