houyaf 3 rokov pred
rodič
commit
dd20f7529a

+ 18 - 5
src/api/repo/repoApi.ts

@@ -7,7 +7,7 @@ import apiRequest from '@/network/http/apiRequest'
  */
 export function getRepoByList(data: any) {
   return apiRequest({
-    url: '/repo/type',
+    url: '/repo',
     method: 'GET',
     params: data,
   })
@@ -15,12 +15,25 @@ export function getRepoByList(data: any) {
 
 /**
  * 根据Id获取Repo
+ * @param repoTypeId
+ * @returns
+ */
+export function getRepoListById(repoTypeId: number) {
+  return apiRequest({
+    url: `/repo/${repoTypeId}`,
+    method: 'GET',
+  })
+}
+
+/**
+ * 根据Id获取Repo
+ * @param repoTypeId
  * @param repoId
  * @returns
  */
-export function getRepoById(repoId: number) {
+export function getRepoById(repoTypeId: number, repoId: number) {
   return apiRequest({
-    url: `/repo/${repoId}`,
+    url: `/repo/${repoTypeId}/${repoId}`,
     method: 'GET',
   })
 }
@@ -56,9 +69,9 @@ export function updateRepo(data: any) {
  * @param repoId
  * @returns
  */
-export function deleteRepoById(repoId: number) {
+export function deleteRepoById(repoTypeId: number, repoId: number) {
   return apiRequest({
-    url: `/repo/${repoId}`,
+    url: `/repo/${repoTypeId}/${repoId}`,
     method: 'DELETE',
   })
 }

+ 19 - 5
src/api/repo/repoCatApi.ts

@@ -1,7 +1,7 @@
 import apiRequest from '@/network/http/apiRequest'
 
 /**
- * 获取DBType列表
+ * 获取RepoCat列表
  * @param data
  * @returns
  */
@@ -14,10 +14,23 @@ export function getRepoCatByList(data: any) {
 }
 
 /**
- * 根据Id获取DBType
+ * 根据Id获取RepoCat
  * @param repoTypeId
  * @returns
  */
+export function getRepoCatListById(repoTypeId: number) {
+  return apiRequest({
+    url: `/repo/cat/${repoTypeId}`,
+    method: 'GET',
+  })
+}
+
+/**
+ * 根据Id获取RepoCat
+ * @param repoTypeId
+ * @param repoCatId
+ * @returns
+ */
 export function getRepoCatById(repoTypeId: number, repoCatId: number) {
   return apiRequest({
     url: `/repo/cat/${repoTypeId}/${repoCatId}`,
@@ -26,7 +39,7 @@ export function getRepoCatById(repoTypeId: number, repoCatId: number) {
 }
 
 /**
- * 添加DBType
+ * 添加RepoCat
  * @param data
  * @returns
  */
@@ -39,7 +52,7 @@ export function createRepoCat(data: any) {
 }
 
 /**
- * 更新DBType
+ * 更新RepoCat
  * @param data
  * @returns
  */
@@ -52,8 +65,9 @@ export function updateRepoCat(data: any) {
 }
 
 /**
- * 删除DBType
+ * 删除RepoCat
  * @param repoTypeId
+ * @param repoCatId
  * @returns
  */
 export function deleteRepoCatById(repoTypeId: number, repoCatId: number) {

+ 1 - 1
src/components/LayoutContainer/index.vue

@@ -79,7 +79,7 @@ const enabledRightSide = computed(() => {
   .left-side,
   .right-side,
   .main {
-    --container-padding: 20px;
+    --container-padding: 10px;
 
     border-radius: 10px;
     height: 100%;

+ 13 - 0
src/router/modules/repo.ts

@@ -26,6 +26,19 @@ const routes: RouteRecordRaw[] = [
       },
 
       {
+        path: 'detail/:repoTypeId/:repoId',
+        name: 'repoDBDetails',
+        component: () => import('@/views/repository/db/index.vue'),
+        meta: {
+          title: '数据库',
+          sidebar: false,
+          activeMenu: '/repo',
+          cache: true,
+          noCache: 'repoDBDetails',
+        },
+      },
+
+      {
         path: 'access',
         name: 'repo_access',
         component: () => import('@/views/repository/access/index.vue'),

+ 4 - 4
src/router/modules/system.ts

@@ -106,11 +106,11 @@ const routes: RouteRecordRaw[] = [
         },
       },
       {
-        path: 'database_type',
-        name: 'database_type',
-        component: () => import('@/views/database/type/index.vue'),
+        path: 'repo_cat',
+        name: 'repo_cat',
+        component: () => import('@/views/repository/cat/index.vue'),
         meta: {
-          title: '数据库类型',
+          title: '库类型',
         },
       },
     ],

+ 7 - 6
src/views/api/api/index.vue

@@ -147,8 +147,9 @@ async function onChangeStatus(row: { apiId: number; status: number }) {
               <template #default="{ node, data }">
                 <div class="custom-tree-node">
                   <div class="label" :title="node.label">
-                    <el-icon v-if="data.isLeaf > 0" size="16px" style="margin-right: 5px;">
-                      <svg-icon name="uim:box" />
+                    <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 }}
@@ -185,17 +186,17 @@ async function onChangeStatus(row: { apiId: number; status: number }) {
 
             <el-table-column prop="apiMethod" label="请求" header-align="center" align="center" width="100">
               <template #default="scope">
-                <span> {{ httpMethod(scope.row.apiMethod) }} </span>
+                <el-tag type="warning"> {{ httpMethod(scope.row.apiMethod) }} </el-tag>
               </template>
             </el-table-column>
 
-            <el-table-column prop="apiCode" label="url" header-align="left" align="left" width="120">
+            <el-table-column prop="apiCode" label="url" header-align="center" align="left" width="200">
               <template #default="scope">
-                <span> /{{ scope.row.objectCode }}/{{ scope.row.oamCode }} </span>
+                <el-tag type="success"> /{{ scope.row.objectCode }}/{{ scope.row.oamCode }} </el-tag>
               </template>
             </el-table-column>
 
-            <el-table-column prop="apiDesc" label="说明" header-align="center" align="left">
+            <el-table-column prop="apiDesc" label="说明" header-align="left" align="left">
               <template #default="scope">
                 <span> {{ scope.row.apiDesc }} </span>
               </template>

+ 5 - 4
src/views/api/log/index.vue

@@ -65,10 +65,10 @@ const getData = async () => {
   if (data && data.length > 0) {
     state.curBizId = data[0].bizId
 
-    data.forEach((biz: { label: string; bizTitle: string; objects: any; children: any; isLeaf: boolean }) => {
+    data.forEach((biz: { label: string; bizTitle: string; children: any; isLeaf: boolean }) => {
       biz.label = biz.bizTitle
       biz.isLeaf = false
-      const objects = biz.objects
+      const objects = biz.children
       objects.forEach((object: { label: string; objectTitle: string; isLeaf: boolean }) => {
         object.label = object.objectTitle
         object.isLeaf = true
@@ -131,8 +131,9 @@ const onReqDel = async (data: { apiTitle: any; reqId: number }) => {
               <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 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 }}

+ 0 - 1
src/views/biz/object/index.vue

@@ -10,7 +10,6 @@ import { getObjectById } from '@/api/biz/bizObjectApi'
 import useSettingsStore from '@/store/modules/settings'
 
 const settingsStore = useSettingsStore()
-
 const router = useRouter()
 const tabbar = useTabbar()
 const route = useRoute()

+ 116 - 0
src/views/repository/cat/components/RepoCat.vue

@@ -0,0 +1,116 @@
+<route lang="yaml">
+meta:
+  enabled: false
+</route>
+
+<script lang="ts" setup name="repoCat">
+import { ElMessage } from 'element-plus'
+import type { FormInstance, FormRules } from 'element-plus'
+import { createRepoCat, getRepoCatById, updateRepoCat } from '@/api/repo/repoCatApi'
+const emit = defineEmits(['success'])
+
+const formRef = ref<FormInstance>()
+const formRules = ref<FormRules>({
+  repoCatTitle: [
+    { required: true, message: '请输入标题', trigger: 'blur' },
+  ],
+  repoCatDesc: [
+    { required: false, message: '请输入描述', trigger: 'blur' },
+  ],
+})
+
+const state = reactive({
+  title: '',
+  dialogVisible: false,
+  loading: false,
+  formData: {
+    repoTypeId: 0,
+    repoCatId: 0,
+    repoCatTitle: '',
+    repoCatDesc: '',
+  },
+  actionType: 1,
+})
+
+onMounted(() => {})
+
+const getData = async (repoTypeId: number, repoCatId: number) => {
+  state.loading = true
+  const { data } = await getRepoCatById(repoTypeId, repoCatId)
+  state.loading = false
+  state.formData = data
+}
+
+function onSubmit() {
+  formRef.value && formRef.value.validate(async (valid) => {
+    if (valid) {
+      if (state.actionType === 1) {
+        const { msg } = await createRepoCat(state.formData)
+        ElMessage.success(msg)
+        state.dialogVisible = false
+        emit('success')
+      }
+      else {
+        const { msg } = await updateRepoCat(state.formData)
+        ElMessage.success(msg)
+        state.dialogVisible = false
+        emit('success')
+      }
+    }
+  })
+}
+
+function onCancel() {
+  state.dialogVisible = false
+}
+
+function resetFormData() {
+  state.formData = {
+    repoTypeId: 0,
+    repoCatId: 0,
+    repoCatTitle: '',
+    repoCatDesc: '',
+  }
+}
+
+defineExpose({
+  showAddModel(repoTypeId: number) {
+    resetFormData()
+    state.title = '新增'
+    state.actionType = 1
+    state.formData.repoTypeId = repoTypeId
+    state.dialogVisible = true
+  },
+  showEditModel(repoTypeId: number, repoCatId: number) {
+    resetFormData()
+    state.title = '编辑'
+    state.actionType = 2
+    state.dialogVisible = true
+    getData(repoTypeId, repoCatId)
+  },
+
+})
+</script>
+
+<template>
+  <el-drawer v-model="state.dialogVisible" :title="state.title" width="600px" :close-on-click-modal="false" append-to-body destroy-on-close>
+    <el-form ref="formRef" :model="state.formData" :rules="formRules" label-width="120px" label-suffix=":">
+      <el-form-item label="分类名称" prop="repoCatTitle">
+        <el-input v-model="state.formData.repoCatTitle" placeholder="请输入标题" />
+      </el-form-item>
+
+      <el-form-item label="简要说明" prop="repoCatDesc">
+        <el-input v-model="state.formData.repoCatDesc" type="textarea" rows="10" placeholder="请输入简要说明" />
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <el-button size="large" @click="onCancel">
+        取消
+      </el-button>
+      <el-button type="primary" size="large" @click="onSubmit">
+        保存
+      </el-button>
+    </template>
+  </el-drawer>
+</template>

+ 274 - 0
src/views/repository/cat/index.vue

@@ -0,0 +1,274 @@
+<script lang="ts" setup name="oc_cat_List">
+import { ElMessage, ElMessageBox } from 'element-plus'
+import RepoCatComponent from './components/RepoCat.vue'
+import { getRepoTypeByList } from '@/api/repo/repoTypeApi'
+import { deleteRepoCatById, getRepoCatListById } from '@/api/repo/repoCatApi'
+
+interface TreeNode {
+  label: string
+  isLeaf: boolean
+  repoTypeId: number
+  children?: TreeNode[]
+}
+
+interface Object {
+  repoTypeId: number
+  repoCatId: number
+  repoCatTitle: string
+  repoCatDesc: string
+}
+
+const state = reactive({
+  loading: false,
+  keywords: '',
+  treeData: [] as TreeNode[],
+  curRepoTypeId: 0,
+  repoCatList: [] as Object[],
+  dialogState: 1,
+  search: {
+    keywords: '',
+  },
+})
+
+const leftTreeRef = ref()
+const getRepoCatData = async () => {
+  const curRepoTypeId = state.curRepoTypeId
+  if (curRepoTypeId > 0) {
+    state.loading = true
+    const { data } = await getRepoCatListById(curRepoTypeId)
+    state.repoCatList = data
+    state.loading = false
+  }
+}
+
+const getRepoTypeData = async () => {
+  const { data } = await getRepoTypeByList({})
+  const children: TreeNode[] = []
+  data.forEach((item: any) => {
+    return children.push({
+      label: item.repoTypeTitle,
+      repoTypeId: item.repoTypeId,
+      isLeaf: true,
+    })
+  })
+  state.treeData = [
+    {
+      label: '数据仓库类型',
+      isLeaf: false,
+      repoTypeId: -1,
+      children,
+    },
+  ]
+
+  if (data && data.length > 0) {
+    state.curRepoTypeId = data[0].repoTypeId
+    nextTick(() => {
+      leftTreeRef.value.setCurrentKey(data[0].repoTypeId)
+    })
+    await getRepoCatData()
+  }
+}
+
+onMounted(() => {
+  getRepoTypeData()
+})
+
+// 模型选择
+const onTreeNodeClick = (node: TreeNode) => {
+  if (node.isLeaf) {
+    state.curRepoTypeId = node.repoTypeId
+    getRepoCatData()
+  }
+}
+
+const repoCatTableRef = ref()
+const repoCatRef = ref()
+
+// 检索对象
+const onSearch = () => {
+  getRepoCatData()
+}
+
+// 新增
+const onRepoCatAdd = () => {
+  const repoTypeId = state.curRepoTypeId
+  if (repoTypeId > 0) {
+    repoCatRef.value.showAddModel(repoTypeId)
+  }
+}
+
+// 编辑
+const onRepoCatEdit = (row: { repoCatId: number }) => {
+  const repoTypeId = state.curRepoTypeId
+  if (repoTypeId > 0) {
+    repoCatRef.value.showEditModel(repoTypeId, row.repoCatId)
+  }
+}
+
+// 删除对象
+const onRepoCatDelete = (row: any) => {
+  const { ocTypeId, ocCatId, ocCatTitle } = row
+  ElMessageBox.confirm(`确认删除「${ocCatTitle}」吗?`, '确认信息').then(async () => {
+    const { msg } = await deleteRepoCatById(ocTypeId, ocCatId)
+    ElMessage.success(msg)
+    await getRepoCatData()
+  })
+}
+</script>
+
+<template>
+  <div class="absolute-container">
+    <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="repoCatId" @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="ep:office-building" />
+                    </el-icon>
+                    <div class="text">
+                      {{ data.label }}
+                    </div>
+                  </div>
+                </div>
+              </template>
+            </ElTree>
+          </el-scrollbar>
+        </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>
+
+              <el-button size="default" @click.stop="onRepoCatAdd">
+                <template #icon>
+                  <el-icon>
+                    <svg-icon name="i-ep:plus" />
+                  </el-icon>
+                </template>
+                数据仓库分类
+              </el-button>
+            </template>
+          </tool-bar>
+
+          <el-table ref="repoCatTableRef" v-loading="state.loading" class="list-table" :data="state.repoCatList" size="small" border stripe highlight-current-row height="100%">
+            <el-table-column type="index" label="序号" header-align="center" align="center" width="60" />
+
+            <el-table-column prop="repoCatTitle" label="名称" header-align="center" align="center" width="200">
+              <template #default="scope">
+                <span>{{ scope.row.repoCatTitle }}</span>
+              </template>
+            </el-table-column>
+
+            <el-table-column prop="repoCatDesc" label="说明" header-align="center" align="left">
+              <template #default="scope">
+                <span>{{ scope.row.repoCatDesc }}</span>
+              </template>
+            </el-table-column>
+
+            <el-table-column label="操作" header-align="center" align="center" width="220">
+              <template #default="scope">
+                <el-button type="warning" size="small" plain @click="onRepoCatEdit(scope.row)">编辑</el-button>
+                <el-button v-if="scope.row.isFixed <= 0" type="danger" size="small" plain @click="onRepoCatDelete(scope.row)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+      </LayoutContainer>
+    </div>
+    <RepoCatComponent ref="repoCatRef" @success="getRepoCatData" />
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.container {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+}
+
+.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>

+ 34 - 3
src/views/repository/db/index.vue

@@ -6,6 +6,15 @@ meta:
 <script lang="ts" setup>
 import { getModelTreeData } from '@/api/model/modelApi'
 import { getTableDataByList, getTableFieldsByList } from '@/api/repo/repoDBApi'
+import useSettingsStore from '@/store/modules/settings'
+
+const settingsStore = useSettingsStore()
+const router = useRouter()
+const tabbar = useTabbar()
+const route = useRoute()
+
+const repoTypeId = parseInt(route.params.repoTypeId.toString())
+const repoId = parseInt(route.params.repoId.toString())
 
 interface TreeNode {
   label: string
@@ -93,13 +102,31 @@ const tableDataRef = ref()
 const onSearch = () => {
   getData()
 }
+
+// 返回列表页
+function goBack() {
+  if (settingsStore.settings.tabbar.enable && settingsStore.settings.tabbar.mergeTabsBy !== 'activeMenu') {
+    tabbar.close({ name: 'repo_index' })
+  }
+  else {
+    router.push({ name: 'repo_index' })
+  }
+}
 </script>
 
 <template>
   <div class="absolute-container">
-    <tool-header title="数据仓库">
-      <template #right />
-    </tool-header>
+    <page-header title="数据仓库">
+      <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="250px" hide-left-side-toggle>
         <template #leftSide>
@@ -153,6 +180,10 @@ const onSearch = () => {
 
 <style lang="scss" scoped>
 .absolute-container {
+  .page-header {
+    margin-bottom: 0;
+  }
+
   :deep(.left-side) {
     display: flex;
     flex-direction: column;

+ 189 - 0
src/views/repository/repo/components/Repo.vue

@@ -0,0 +1,189 @@
+<route lang="yaml">
+meta:
+  enabled: false
+</route>
+
+<script lang="ts" setup>
+import { ElMessage } from 'element-plus'
+import type { FormInstance, FormRules } from 'element-plus'
+import { createRepo, getRepoById, updateRepo } from '@/api/repo/repoApi'
+import RepoCatSelector from '@/views/repository/repo/components/RepoCatSelector.vue'
+
+const emit = defineEmits(['success'])
+
+const formRef = ref<FormInstance>()
+const formRules = ref<FormRules>({
+  repoTitle: [
+    { required: true, message: '请输入标题', trigger: 'blur' },
+  ],
+  repoDesc: [
+    { required: false, message: '请输入描述', trigger: 'blur' },
+  ],
+})
+
+const state = reactive({
+  title: '',
+  dialogVisible: false,
+  loading: false,
+  search: {
+    repoTypeId: 0,
+    repoId: 0,
+  },
+  formData: {
+    repoId: 0,
+    repoTitle: '',
+    repoTypeId: 0,
+    repoCatId: 0,
+    repoHost: '',
+    repoPort: 0,
+    repoAccount: '',
+    repoPassword: '',
+    repoAccessKey: '',
+    repoSecretKey: '',
+    repoTarget: '',
+    repoDesc: '',
+  },
+  actionType: 1,
+})
+
+onMounted(() => {})
+
+const getData = async () => {
+  const { repoTypeId, repoId } = state.search
+  state.loading = true
+  const { data } = await getRepoById(repoTypeId, repoId)
+  state.loading = false
+  state.formData = data
+}
+
+function onSubmit() {
+  formRef.value && formRef.value.validate(async (valid) => {
+    if (valid) {
+      if (state.actionType === 1) {
+        const { msg } = await createRepo(state.formData)
+        ElMessage.success(msg)
+        state.dialogVisible = false
+        emit('success')
+      }
+      else {
+        const { msg } = await updateRepo(state.formData)
+        ElMessage.success(msg)
+        state.dialogVisible = false
+        emit('success')
+      }
+    }
+  })
+}
+
+function onCancel() {
+  state.dialogVisible = false
+}
+
+function resetFormData() {
+  state.formData = {
+    repoId: 0,
+    repoTitle: '',
+    repoTypeId: 0,
+    repoCatId: 0,
+    repoHost: '',
+    repoPort: 0,
+    repoAccount: '',
+    repoPassword: '',
+    repoAccessKey: '',
+    repoSecretKey: '',
+    repoTarget: '',
+    repoDesc: '',
+  }
+}
+
+defineExpose({
+  showAddModel(repoTypeId: number) {
+    resetFormData()
+    if (repoTypeId === 1) {
+      state.title = '新增数据库'
+    }
+    else if (repoTypeId === 2) {
+      state.title = '新增文件服务器'
+    }
+    else {
+      state.title = '新增高速缓冲'
+    }
+    state.actionType = 1
+    state.search.repoTypeId = repoTypeId
+    state.formData.repoTypeId = repoTypeId
+    state.dialogVisible = true
+  },
+
+  showEditModel(repoTypeId: number, repoId: number) {
+    resetFormData()
+    state.title = '编辑'
+    state.actionType = 2
+    state.search.repoTypeId = repoTypeId
+    state.search.repoId = repoId
+    state.dialogVisible = true
+    getData()
+  },
+
+})
+</script>
+
+<template>
+  <el-drawer v-model="state.dialogVisible" :title="state.title" width="700px" :close-on-click-modal="false" append-to-body destroy-on-close>
+    <div v-loading="state.loading">
+      <el-form ref="formRef" :model="state.formData" :rules="formRules" label-width="120px" label-suffix=":">
+        <el-form-item label="标题" prop="repoTitle">
+          <el-input v-model="state.formData.repoTitle" placeholder="标题" />
+        </el-form-item>
+
+        <el-form-item label="类别" prop="dbTypeTitle">
+          <RepoCatSelector v-model="state.formData.repoCatId" :repo-type-id="state.formData.repoTypeId" />
+        </el-form-item>
+
+        <el-form-item label="主机" prop="repoHost">
+          <el-col :span="16">
+            <el-input v-model="state.formData.repoHost" placeholder="请输入主机" />
+          </el-col>
+          <el-col :span="1">
+            :
+          </el-col>
+          <el-col :span="7">
+            <el-input v-model="state.formData.repoPort" type="number" placeholder="请输入端口" />
+          </el-col>
+        </el-form-item>
+
+        <el-form-item label="账号" prop="repoAccount">
+          <el-input v-model="state.formData.repoAccount" placeholder="请输入账号" />
+        </el-form-item>
+
+        <el-form-item label="密码" prop="repoPassword">
+          <el-input v-model="state.formData.repoPassword" placeholder="请输入密码" />
+        </el-form-item>
+
+        <el-form-item label="Access Key" prop="repoAccessKey">
+          <el-input v-model="state.formData.repoAccessKey" placeholder="请输入Access Key" />
+        </el-form-item>
+
+        <el-form-item label="Secret key" prop="repoSecretKey">
+          <el-input v-model="state.formData.repoSecretKey" placeholder="请输入Secret Key" />
+        </el-form-item>
+
+        <el-form-item label="目标库" prop="repoTarget">
+          <el-input v-model="state.formData.repoTarget" placeholder="请输入Target" />
+        </el-form-item>
+
+        <el-form-item label="简要说明" prop="repoDesc">
+          <el-input v-model="state.formData.repoDesc" type="textarea" rows="5" placeholder="请输入简要说明" />
+        </el-form-item>
+      </el-form>
+    </div>
+
+    <template #footer>
+      <el-button size="large" @click="onCancel">
+        取消
+      </el-button>
+      <el-button type="primary" size="large" @click="onSubmit">
+        保存
+      </el-button>
+    </template>
+  </el-drawer>
+</template>

+ 56 - 0
src/views/repository/repo/components/RepoCatSelector.vue

@@ -0,0 +1,56 @@
+<script lang="ts" setup name="RepoCatSelector">
+import { getRepoCatListById } from '@/api/repo/repoCatApi'
+const props = withDefaults(defineProps<{
+  modelValue: number
+  repoTypeId: number
+}>(), {
+  modelValue: 0,
+  repoTypeId: 0,
+})
+
+const emit = defineEmits(['update:modelValue'])
+interface RepoCat {
+  repoTypeId: number
+  repoCatId: number
+  repoCatTitle: string
+}
+
+const repoCatId = computed({
+  get: () => {
+    return props.modelValue
+  },
+  set: (val) => {
+    emit('update:modelValue', val)
+  },
+})
+
+const state = reactive({
+  loading: false,
+  dataList: [] as RepoCat[],
+})
+
+const getData = async () => {
+  const repoTypeId = props.repoTypeId
+  if (repoTypeId > 0) {
+    state.loading = true
+    const { data } = await getRepoCatListById(repoTypeId)
+    state.loading = false
+    state.dataList = data
+  }
+}
+onMounted(() => {
+  getData ()
+})
+</script>
+
+<template>
+  <el-select v-model="repoCatId" v-loading="state.loading" style="width: 100%" filterable placeholder="请选择" value-key="repoCatId">
+    <el-option key="0" label="请选择" :value="0" disabled />
+    <el-option
+      v-for="item in state.dataList"
+      :key="item.repoCatId"
+      :label="item.repoCatTitle"
+      :value="item.repoCatId"
+    />
+  </el-select>
+</template>

+ 0 - 117
src/views/repository/repo/components/RepoType.vue

@@ -1,117 +0,0 @@
-<route lang="yaml">
-meta:
-  enabled: false
-</route>
-
-<script lang="ts" setup>
-import { ElMessage } from 'element-plus'
-import type { FormInstance, FormRules } from 'element-plus'
-import { createRepoType, getRepoTypeById, updateRepoType } from '@/api/repo/repoTypeApi'
-const emit = defineEmits(['success'])
-
-const formRef = ref<FormInstance>()
-const formRules = ref<FormRules>({
-  dbTypeTitle: [
-    { required: true, message: '请输入标题', trigger: 'blur' },
-  ],
-  dbTypeDesc: [
-    { required: false, message: '请输入描述', trigger: 'blur' },
-  ],
-})
-
-const state = reactive({
-  title: '',
-  dialogVisible: false,
-  loading: false,
-  formData: {
-    dbTypeId: 0,
-    dbTypeTitle: '',
-    dbTypeDesc: '',
-  },
-  actionType: 1,
-})
-
-onMounted(() => {})
-
-const getData = async (dbTypeId: number) => {
-  state.loading = true
-  const { data } = await getRepoTypeById(dbTypeId)
-  state.loading = false
-  state.formData = data
-}
-
-function onSubmit() {
-  formRef.value && formRef.value.validate(async (valid) => {
-    if (valid) {
-      if (state.actionType === 1) {
-        const { msg } = await createRepoType(state.formData)
-        ElMessage.success(msg)
-        state.dialogVisible = false
-        emit('success')
-      }
-      else {
-        const { msg } = await updateRepoType(state.formData)
-        ElMessage.success(msg)
-        state.dialogVisible = false
-        emit('success')
-      }
-    }
-  })
-}
-
-function onCancel() {
-  state.dialogVisible = false
-}
-
-function resetFormData() {
-  state.formData = {
-    dbTypeId: 0,
-    dbTypeTitle: '',
-    dbTypeDesc: '',
-  }
-}
-
-defineExpose({
-  showAddModel() {
-    resetFormData()
-    state.title = '新增'
-    state.actionType = 1
-    state.dialogVisible = true
-  },
-  showEditModel(dbTypeId: number) {
-    resetFormData()
-    state.title = '编辑'
-    state.actionType = 2
-    state.dialogVisible = true
-    getData(dbTypeId)
-  },
-
-})
-</script>
-
-<template>
-  <div>
-    <el-dialog v-model="state.dialogVisible" :title="state.title" width="600px" :close-on-click-modal="false" append-to-body destroy-on-close>
-      <div v-loading="state.loading">
-        <el-form ref="formRef" :model="state.formData" :rules="formRules" label-width="120px" label-suffix=":">
-          <el-form-item label="分类名称" prop="dbTypeTitle">
-            <el-input v-model="state.formData.dbTypeTitle" placeholder="请输入标题" />
-          </el-form-item>
-
-          <el-form-item label="简要说明" prop="dbTypeDesc">
-            <el-input v-model="state.formData.dbTypeDesc" type="textarea" rows="10" placeholder="请输入简要说明" />
-          </el-form-item>
-        </el-form>
-      </div>
-
-      <template #footer>
-        <el-button size="large" @click="onCancel">
-          取消
-        </el-button>
-        <el-button type="primary" size="large" @click="onSubmit">
-          保存
-        </el-button>
-      </template>
-    </el-dialog>
-  </div>
-</template>

+ 226 - 61
src/views/repository/repo/index.vue

@@ -1,7 +1,12 @@
 <script lang="ts" setup name="DBTypeIndex">
 import { ElMessage, ElMessageBox } from 'element-plus'
-import DBType from './components/RepoType.vue'
-import { deleteRepoTypeById, getRepoTypeByList } from '@/api/repo/repoTypeApi'
+import RepoComponent from './components/Repo.vue'
+import { deleteRepoById, getRepoListById } from '@/api/repo/repoApi'
+import useSettingsStore from '@/store/modules/settings'
+
+const settingsStore = useSettingsStore()
+const router = useRouter()
+const tabbar = useTabbar()
 
 const state = reactive({
   loading: false,
@@ -12,87 +17,245 @@ const state = reactive({
     keywords: '',
   },
   // 列表数据
-  dataList: [],
+  repoDBList: [],
+  repoFileList: [],
+  repoCacheList: [],
 })
 
-const appCatRef = ref()
+const repoRef = ref()
 
-const getDataList = async () => {
+const getRepoList = async (repoTypeId: number) => {
   state.loading = true
-  const { data } = await getRepoTypeByList({})
-  state.dataList = data
+  const { data } = await getRepoListById(repoTypeId)
+  if (repoTypeId === 1) {
+    state.repoDBList = data
+  }
+  else if (repoTypeId === 2) {
+    state.repoFileList = data
+  }
+  else {
+    state.repoCacheList = data
+  }
   state.loading = false
 }
 
+const getRepoData = async () => {
+  await getRepoList(1)
+  await getRepoList(2)
+  await getRepoList(3)
+}
+
 onMounted(() => {
-  getDataList()
+  getRepoData()
 })
 
-function onCreate() {}
+function onRepoAdd(repoTypeId: number) {
+  repoRef.value.showAddModel(repoTypeId)
+}
 
-function onDBTypeAdd() {
-  appCatRef.value.showAddModel()
+function onRepoEdit(row: any) {
+  const { repoTypeId, repoId } = row
+  repoRef.value.showEditModel(repoTypeId, repoId)
 }
 
-function onDBTypeEdit(row: any) {
-  const appCatId = row.appCatId
-  appCatRef.value.showEditModel(appCatId)
+function onRepoDel(row: any) {
+  const { repoId, repoTypeId, repoTitle } = row
+  ElMessageBox.confirm(`确认删除「${repoTitle}」吗?`, '确认信息').then(async () => {
+    const { msg } = await deleteRepoById(repoTypeId, repoId)
+    ElMessage.success(msg)
+    await getRepoList(repoTypeId)
+  }).catch(() => {})
 }
 
-function onDBTypeDel(row: any) {
-  ElMessageBox.confirm(`确认删除「${row.repoTypeTitle}」吗?`, '确认信息').then(async () => {
-    await deleteRepoTypeById(row.repoId)
-    await getDataList()
-    ElMessage.success({
-      message: '删除成功',
-      center: true,
+// 编辑对象
+const onRepoDetails = (row: { repoTypeId: number; repoId: number }) => {
+  if (settingsStore.settings.tabbar.enable && settingsStore.settings.tabbar.mergeTabsBy !== 'activeMenu') {
+    tabbar.open({
+      name: 'repoDBDetails',
+      params: {
+        repoTypeId: row.repoTypeId,
+        repoId: row.repoId,
+      },
     })
-  }).catch(() => {})
+  }
+  else {
+    router.push({
+      name: 'repoDBDetails',
+      params: {
+        repoTypeId: row.repoTypeId,
+        repoId: row.repoId,
+      },
+    })
+  }
 }
 </script>
 
 <template>
-  <div :class="{ 'absolute-container': state.tableAutoHeight }">
-    <page-header title="数据库接入设定">
+  <div class="absolute-container">
+    <page-header title="数据库">
       <template #content>
         <div>
-          系统支持多种数据库接入,用于设定接入参数
+          用于管理各种类型的数据仓库
         </div>
       </template>
-
-      <el-button-group>
-        <el-button type="primary" size="large" plain @click="onDBTypeAdd">
-          <template #icon>
-            <el-icon>
-              <svg-icon name="ep:plus" />
-            </el-icon>
-          </template>
-          新增
-        </el-button>
-      </el-button-group>
     </page-header>
 
-    <page-main>
-      <el-table v-loading="state.loading" class="list-table" :data="state.dataList" border stripe highlight-current-row height="100%">
-        <el-table-column type="index" label="序号" width="60" header-align="center" align="center" />
-
-        <el-table-column prop="appCatTitle" label="名称" header-align="center" align="center" width="200" />
-
-        <el-table-column prop="appCatDesc" label="说明" />
-
-        <el-table-column label="操作" width="250" align="center" fixed="right">
-          <template #default="scope">
-            <el-button type="primary" size="small" plain @click="onDBTypeEdit(scope.row)">
-              编辑
-            </el-button>
-            <el-button v-if="!scope.row.isFixed" type="danger" size="small" plain @click="onDBTypeDel(scope.row)">
-              删除
-            </el-button>
-          </template>
-        </el-table-column>
-      </el-table>
-    </page-main>
-    <DBType ref="appCatRef" @success="getDataList" />
+    <el-row :gutter="20" style="margin: -10px 10px;">
+      <el-col :md="16">
+        <page-main style="margin: 10px 0;">
+          <tool-bar>
+            <template #left>
+              <h3>数据库</h3>
+            </template>
+            <template #right>
+              <el-button type="success" plain @click="onRepoAdd(1)">
+                <template #icon>
+                  <el-icon>
+                    <svg-icon name="i-ep:plus" />
+                  </el-icon>
+                </template>
+              </el-button>
+            </template>
+          </tool-bar>
+
+          <el-table v-loading="state.loading" class="list-table" :data="state.repoDBList" :border="false" :stripe="false" :show-header="false" height="100%">
+            <el-table-column type="index" width="50" fixed="left" />
+
+            <el-table-column prop="repoTitle" label="名称" header-align="center" align="center" width="150">
+              <template #default="scope">
+                <el-icon size="16px" style="margin-right: 5px;">
+                  <svg-icon name="ep:coin" />
+                </el-icon>
+                <span>{{ scope.row.repoTitle }}</span>
+              </template>
+            </el-table-column>
+
+            <el-table-column prop="repoCatTitle" label="类型" header-align="center" align="center" width="150">
+              <template #default="scope">
+                <el-tag type="success">
+                  {{ scope.row.repoCatTitle }}
+                </el-tag>
+              </template>
+            </el-table-column>
+
+            <el-table-column prop="repoDesc" label="说明" header-align="left" align="left">
+              <template #default="scope">
+                <span>{{ scope.row.repoDesc }}</span>
+              </template>
+            </el-table-column>
+
+            <el-table-column label="操作" width="220" header-align="center" align="right" fixed="right">
+              <template #default="scope">
+                <el-button type="primary" size="small" plain @click="onRepoDetails(scope.row)">
+                  详情
+                </el-button>
+                <el-button type="warning" size="small" plain @click="onRepoEdit(scope.row)">
+                  编辑
+                </el-button>
+                <el-button v-if="!scope.row.isFixed" type="danger" size="small" plain @click="onRepoDel(scope.row)">
+                  删除
+                </el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </page-main>
+      </el-col>
+
+      <el-col :md="8">
+        <page-main style="margin: 10px 0;">
+          <tool-bar>
+            <template #left>
+              <h3>文件服务器</h3>
+            </template>
+            <template #right>
+              <el-button type="success" plain @click="onRepoAdd(2)">
+                <template #icon>
+                  <el-icon>
+                    <svg-icon name="i-ep:plus" />
+                  </el-icon>
+                </template>
+              </el-button>
+            </template>
+          </tool-bar>
+
+          <el-table v-loading="state.loading" class="list-table" :data="state.repoFileList" :border="false" :stripe="false" :show-header="false" height="100%">
+            <el-table-column type="index" label="序号" width="50" header-align="center" align="center" />
+
+            <el-table-column prop="repoTitle" label="名称" header-align="center" align="center" width="100">
+              <template #default="scope">
+                <el-icon size="16px" style="margin-right: 5px;">
+                  <svg-icon name="ep:files" />
+                </el-icon>
+                <span>{{ scope.row.repoTitle }}</span>
+              </template>
+            </el-table-column>
+
+            <el-table-column prop="repoTitle" label="名称" header-align="center" align="center">
+              <template #default="scope">
+                <el-tag type="warning">
+                  {{ scope.row.repoCatTitle }}
+                </el-tag>
+              </template>
+            </el-table-column>
+
+            <el-table-column label="操作" width="150" align="center" fixed="right">
+              <template #default="scope">
+                <el-button type="warning" size="small" plain @click="onRepoEdit(scope.row)">
+                  编辑
+                </el-button>
+                <el-button v-if="!scope.row.isFixed" type="danger" size="small" plain @click="onRepoDel(scope.row)">
+                  删除
+                </el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </page-main>
+
+        <page-main style="margin: 10px 0;">
+          <tool-bar>
+            <template #left>
+              <h3>高速缓存</h3>
+            </template>
+            <template #right>
+              <el-button type="success" plain @click="onRepoAdd(3)">
+                <template #icon>
+                  <el-icon>
+                    <svg-icon name="i-ep:plus" />
+                  </el-icon>
+                </template>
+              </el-button>
+            </template>
+          </tool-bar>
+          <el-table v-loading="state.loading" class="list-table" :data="state.repoCacheList" :border="false" :stripe="false" :show-header="false" height="100%">
+            <el-table-column type="index" label="序号" width="50" header-align="center" align="center" />
+
+            <el-table-column prop="repoTitle" label="名称" header-align="center" align="center" width="100">
+              <template #default="scope">
+                <span>{{ scope.row.repoTitle }}</span>
+              </template>
+            </el-table-column>
+
+            <el-table-column prop="repoTitle" label="名称" header-align="center" align="center">
+              <template #default="scope">
+                <span>{{ scope.row.repoCatTitle }}</span>
+              </template>
+            </el-table-column>
+
+            <el-table-column label="操作" width="150" align="center" fixed="right">
+              <template #default="scope">
+                <el-button type="warning" size="small" plain @click="onRepoEdit(scope.row)">
+                  编辑
+                </el-button>
+                <el-button v-if="!scope.row.isFixed" type="danger" size="small" plain @click="onRepoDel(scope.row)">
+                  删除
+                </el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </page-main>
+      </el-col>
+    </el-row>
+    <RepoComponent ref="repoRef" @success="getRepoData" />
   </div>
 </template>
 
@@ -104,10 +267,6 @@ function onDBTypeDel(row: any) {
   display: flex;
   flex-direction: column;
 
-  .page-header {
-    margin-bottom: 0;
-  }
-
   .page-main {
     // 让 page-main 的高度自适应
     flex: 1;
@@ -115,6 +274,12 @@ function onDBTypeDel(row: any) {
     display: flex;
     flex-direction: column;
 
+    .tool-bar {
+      h3{
+        color: #757d87;
+      }
+    }
+
     .search-container {
       margin-bottom: 0;
     }

+ 4 - 5
src/views/system/group/index.vue

@@ -359,16 +359,15 @@ const getGroupList = () => {}
   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;
-      padding: 0px;
-    }
   }
 }
 

+ 0 - 4
src/views/system/setting/oc_cat/index.vue

@@ -203,10 +203,6 @@ const onOcCatDelete = (row: any) => {
 }
 
 .absolute-container {
-  .flex-container {
-    padding: 0px;
-  }
-
   :deep(.left-side) {
     display: flex;
     flex-direction: column;