zs 5 ヶ月 前
コミット
3126a4764a

+ 1 - 1
src/lang/package/zh-cn/common.js

@@ -5,8 +5,8 @@ export default {
   update: '修改',
   update: '修改',
   delete: '删除',
   delete: '删除',
   exam: '审核',
   exam: '审核',
+  resetPwd: '重置密码',
   dict: '字典数据',
   dict: '字典数据',
-  sign: '报名管理',
   delete_confirm: '您确定删除该数据?',
   delete_confirm: '您确定删除该数据?',
   search: '查询',
   search: '查询',
   reset: '重置',
   reset: '重置',

+ 12 - 0
src/router/index.js

@@ -4,6 +4,9 @@ export const homeIndex = () => import('@/views/home/index.vue')
 export const Layout = () => import('@/layout/index.vue')
 export const Layout = () => import('@/layout/index.vue')
 import { routes as systemRoutes } from './modules/system'
 import { routes as systemRoutes } from './modules/system'
 import { routes as userRoutes } from './modules/user'
 import { routes as userRoutes } from './modules/user'
+import { routes as jobRoutes } from './modules/job'
+import { routes as colonyRoutes } from './modules/colony'
+import { routes as controlRoutes } from './modules/control'
 // 静态路由
 // 静态路由
 export const constantRoutes = [
 export const constantRoutes = [
   {
   {
@@ -41,6 +44,15 @@ export const constantRoutes = [
       },
       },
       ...systemRoutes,
       ...systemRoutes,
       ...userRoutes,
       ...userRoutes,
+      ...jobRoutes,
+      ...colonyRoutes,
+      ...controlRoutes,
+      {
+        path: '/operate',
+        name: 'operate',
+        meta: { title: '操作日志' },
+        component: () => import('@/views/operate/index.vue')
+      },
       {
       {
         path: '/acccount',
         path: '/acccount',
         name: 'acccount',
         name: 'acccount',

+ 28 - 0
src/router/modules/colony.js

@@ -0,0 +1,28 @@
+export const routes = [
+  {
+    path: '/colony',
+    name: 'colony',
+    redirect: 'noredirect',
+    meta: {
+      title: '集群管理'
+    },
+    children: [
+      {
+        path: '/colony/partition',
+        name: 'colony_partition',
+        meta: {
+          title: '分区管理'
+        },
+        component: () => import('@/views/colony/partition/index.vue')
+      },
+      {
+        path: '/colony/node',
+        name: 'colony_node',
+        meta: {
+          title: '节点管理'
+        },
+        component: () => import('@/views/colony/node/index.vue')
+      }
+    ]
+  }
+]

+ 36 - 0
src/router/modules/control.js

@@ -0,0 +1,36 @@
+export const routes = [
+  {
+    path: '/control',
+    name: 'control',
+    redirect: 'noredirect',
+    meta: {
+      title: '监控管理'
+    },
+    children: [
+      {
+        path: '/control/resource',
+        name: 'control_resource',
+        meta: {
+          title: '资源管理'
+        },
+        component: () => import('@/views/control/resource/index.vue')
+      },
+      {
+        path: '/control/performance',
+        name: 'control_performance',
+        meta: {
+          title: '性能管理'
+        },
+        component: () => import('@/views/control/performance/index.vue')
+      },
+      {
+        path: '/control/statement',
+        name: 'control_statement',
+        meta: {
+          title: '报表管理'
+        },
+        component: () => import('@/views/control/statement/index.vue')
+      }
+    ]
+  }
+]

+ 36 - 0
src/router/modules/job.js

@@ -0,0 +1,36 @@
+export const routes = [
+  {
+    path: '/job',
+    name: 'job',
+    redirect: 'noredirect',
+    meta: {
+      title: '作业管理'
+    },
+    children: [
+      {
+        path: '/job/realtime',
+        name: 'job_realtime',
+        meta: {
+          title: '实时作业'
+        },
+        component: () => import('@/views/job/realtime/index.vue')
+      },
+      {
+        path: '/job/history',
+        name: 'job_history',
+        meta: {
+          title: '历史作业'
+        },
+        component: () => import('@/views/job/history/index.vue')
+      },
+      {
+        path: '/job/monitor',
+        name: 'job_monitor',
+        meta: {
+          title: '监控作业'
+        },
+        component: () => import('@/views/job/monitor/index.vue')
+      }
+    ]
+  }
+]

+ 9 - 1
src/router/modules/system.js

@@ -30,7 +30,15 @@ export const routes = [
           title: '字典管理'
           title: '字典管理'
         },
         },
         component: () => import('@/views/system/dict/index.vue')
         component: () => import('@/views/system/dict/index.vue')
-      }
+      },
+      {
+        path: '/system/organization',
+        name: 'system_organization',
+        meta: {
+          title: '组织管理'
+        },
+        component: () => import('@/views/system/organization/index.vue')
+      },
     ]
     ]
   }
   }
 ]
 ]

+ 2 - 2
src/store/api/platform/demand.js

@@ -1,10 +1,10 @@
 import { defineStore } from 'pinia'
 import { defineStore } from 'pinia'
 import { AxiosWrapper } from '@/utils/axios-wrapper'
 import { AxiosWrapper } from '@/utils/axios-wrapper'
 import { get } from 'lodash-es'
 import { get } from 'lodash-es'
-const url = '/demand'
+const url = '/history'
 const axios = new AxiosWrapper()
 const axios = new AxiosWrapper()
 
 
-export const DemandStore = defineStore('demand', () => {
+export const HistoryStore = defineStore('history', () => {
   const query = async ({ skip = 0, limit = undefined, ...info } = {}) => {
   const query = async ({ skip = 0, limit = undefined, ...info } = {}) => {
     let cond = {}
     let cond = {}
     if (skip) cond.skip = skip
     if (skip) cond.skip = skip

+ 2 - 2
src/store/api/platform/match.js

@@ -1,10 +1,10 @@
 import { defineStore } from 'pinia'
 import { defineStore } from 'pinia'
 import { AxiosWrapper } from '@/utils/axios-wrapper'
 import { AxiosWrapper } from '@/utils/axios-wrapper'
 import { get } from 'lodash-es'
 import { get } from 'lodash-es'
-const url = '/match'
+const url = '/realtime'
 const axios = new AxiosWrapper()
 const axios = new AxiosWrapper()
 
 
-export const MatchStore = defineStore('match', () => {
+export const RealtimeStore = defineStore('realtime', () => {
   const query = async ({ skip = 0, limit = undefined, ...info } = {}) => {
   const query = async ({ skip = 0, limit = undefined, ...info } = {}) => {
     let cond = {}
     let cond = {}
     if (skip) cond.skip = skip
     if (skip) cond.skip = skip

+ 0 - 40
src/store/api/platform/news.js

@@ -1,40 +0,0 @@
-import { defineStore } from 'pinia'
-import { AxiosWrapper } from '@/utils/axios-wrapper'
-import { get } from 'lodash-es'
-const url = '/news'
-const axios = new AxiosWrapper()
-
-export const NewsStore = defineStore('news', () => {
-  const query = async ({ skip = 0, limit = undefined, ...info } = {}) => {
-    let cond = {}
-    if (skip) cond.skip = skip
-    if (limit) cond.limit = limit
-    cond = { ...cond, ...info }
-    const res = await axios.$get(`${url}`, cond)
-    return res
-  }
-  const fetch = async (payload) => {
-    const res = await axios.$get(`${url}/${payload}`)
-    return res
-  }
-  const create = async (payload) => {
-    const res = await axios.$post(`${url}`, payload)
-    return res
-  }
-  const update = async (payload) => {
-    const id = get(payload, 'id', get(payload, '_id'))
-    const res = await axios.$post(`${url}/${id}`, payload)
-    return res
-  }
-  const del = async (payload) => {
-    const res = await axios.$delete(`${url}/${payload}`)
-    return res
-  }
-  return {
-    query,
-    fetch,
-    create,
-    update,
-    del
-  }
-})

+ 20 - 0
src/views/colony/node/index.vue

@@ -0,0 +1,20 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one"> 节点管理 </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+// 加载中
+const loading = ref(false)
+// 请求
+onMounted(async () => {
+  loading.value = true
+  loading.value = false
+})
+</script>
+<style scoped lang="scss"></style>

+ 20 - 0
src/views/colony/partition/index.vue

@@ -0,0 +1,20 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one"> 分区管理 </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+// 加载中
+const loading = ref(false)
+// 请求
+onMounted(async () => {
+  loading.value = true
+  loading.value = false
+})
+</script>
+<style scoped lang="scss"></style>

+ 20 - 0
src/views/control/performance/index.vue

@@ -0,0 +1,20 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one"> 性能管理 </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+// 加载中
+const loading = ref(false)
+// 请求
+onMounted(async () => {
+  loading.value = true
+  loading.value = false
+})
+</script>
+<style scoped lang="scss"></style>

+ 20 - 0
src/views/control/resource/index.vue

@@ -0,0 +1,20 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one"> 资源管理 </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+// 加载中
+const loading = ref(false)
+// 请求
+onMounted(async () => {
+  loading.value = true
+  loading.value = false
+})
+</script>
+<style scoped lang="scss"></style>

+ 20 - 0
src/views/control/statement/index.vue

@@ -0,0 +1,20 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one"> 报表管理 </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+// 加载中
+const loading = ref(false)
+// 请求
+onMounted(async () => {
+  loading.value = true
+  loading.value = false
+})
+</script>
+<style scoped lang="scss"></style>

+ 98 - 0
src/views/job/history/index.vue

@@ -0,0 +1,98 @@
+<template>
+  <div class="main animate__animated animate__backInRight" v-loading="loading">
+    <custom-search-bar :fields="fields.filter((f) => f.isSearch)" v-model="searchForm" @search="search" @reset="toReset"></custom-search-bar>
+    <custom-button-bar :fields="buttonFields" @add="toAdd"></custom-button-bar>
+    <custom-table :data="data" :fields="fields" @query="search" :total="total" :opera="opera" @edit="toEdit" @delete="toDelete" :select="true"> </custom-table>
+    <el-dialog v-model="dialog" title="数据维护信息" :destroy-on-close="false" @close="toClose" width="50%">
+      <custom-form v-model="form" :fields="fields" :rules="{}" @save="toSave"> </custom-form>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+const $checkRes = inject('$checkRes')
+import { cloneDeep, get } from 'lodash-es'
+const { t } = useI18n()
+// 接口
+import { HistoryStore } from '@/store/api/core/history'
+const store = HistoryStore()
+const data = ref([])
+const searchForm = ref({})
+const fields = [
+  { label: '作业Id', model: 'work_id' },
+  { label: '作业名称', model: 'work_name', isSearch: true },
+  { label: '用户', model: 'user_name', isSearch: true },
+  { label: '组织', model: 'organization', isSearch: true },
+  { label: '状态', model: 'status' },
+  { label: '分区', model: 'partition' },
+  { label: 'CPU总核', model: 'cpu_total' },
+  { label: 'GPU卡数', model: 'cpu_num' },
+  { label: '节点数量', model: 'num' },
+  { label: '运行节点', model: 'node' },
+  { label: '运行时长', model: 'time' },
+  { label: '提交时间', model: 'submission_time', type: 'datetime' },
+  { label: '工作目录', model: 'work_menu' }
+]
+const opera = [
+  { label: t('common.update'), method: 'edit' },
+  { label: t('common.delete'), method: 'delete', confirm: true, type: 'danger' }
+]
+const buttonFields = [{ label: t('common.add'), method: 'add' }]
+let skip = 0
+let limit = inject('limit')
+const total = ref(20)
+// 加载中
+const loading = ref(false)
+const dialog = ref(false)
+const form = ref({})
+// 请求
+onMounted(async () => {
+  loading.value = true
+  await search({ skip, limit })
+  loading.value = false
+})
+const search = async (query = { skip: 0, limit }) => {
+  const info = { skip: query.skip, limit: query.limit, ...searchForm.value }
+  const res = await store.query(info)
+  if (res.errcode == '0') {
+    data.value = res.data.data
+    total.value = res.data.total
+  }
+}
+// 添加
+const toAdd = () => {
+  dialog.value = true
+}
+// 修改
+const toEdit = (data) => {
+  form.value = data
+  dialog.value = true
+}
+// 删除
+const toDelete = async (data) => {
+  const res = await store.del(data._id)
+  if ($checkRes(res, true)) {
+    search({ skip: 0, limit })
+  }
+}
+const toSave = async () => {
+  const data = cloneDeep(form.value)
+  let res
+  if (get(data, '_id')) res = await store.update(data)
+  else res = await store.create({ ...data })
+  if ($checkRes(res, true)) {
+    search({ skip: 0, limit })
+    toClose()
+  }
+}
+// 重置
+const toReset = async () => {
+  searchForm.value = {}
+  await search({ skip, limit })
+}
+const toClose = () => {
+  form.value = {}
+  dialog.value = false
+}
+</script>
+<style scoped lang="scss"></style>

+ 20 - 0
src/views/job/monitor/index.vue

@@ -0,0 +1,20 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one"> 监控作业 </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+// 加载中
+const loading = ref(false)
+// 请求
+onMounted(async () => {
+  loading.value = true
+  loading.value = false
+})
+</script>
+<style scoped lang="scss"></style>

+ 93 - 0
src/views/job/realtime/index.vue

@@ -0,0 +1,93 @@
+<template>
+  <div class="main animate__animated animate__backInRight" v-loading="loading">
+    <custom-search-bar :fields="fields.filter((f) => f.isSearch)" v-model="searchForm" @search="search" @reset="toReset"></custom-search-bar>
+    <custom-button-bar :fields="buttonFields" @add="toAdd"></custom-button-bar>
+    <custom-table :data="data" :fields="fields" @query="search" :total="total" :opera="opera" @edit="toEdit" @delete="toDelete" :select="true"> </custom-table>
+    <el-dialog v-model="dialog" title="数据维护信息" :destroy-on-close="false" @close="toClose" width="50%">
+      <custom-form v-model="form" :fields="fields" :rules="{}" @save="toSave"> </custom-form>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+const $checkRes = inject('$checkRes')
+import { cloneDeep, get } from 'lodash-es'
+const { t } = useI18n()
+// 接口
+import { RealtimeStore } from '@/store/api/core/realtime'
+const store = RealtimeStore()
+const data = ref([])
+const searchForm = ref({})
+const fields = [
+  { label: '作业Id', model: 'work_id' },
+  { label: '作业名称', model: 'work_name', isSearch: true },
+  { label: '用户', model: 'user_name', isSearch: true },
+  { label: '组织', model: 'organization', isSearch: true },
+  { label: '状态', model: 'status' },
+  { label: '运行时长', model: 'time' },
+  { label: '分区', model: 'partition' },
+  { label: '节点列表', model: 'node' }
+]
+const opera = [
+  { label: t('common.update'), method: 'edit' },
+  { label: t('common.delete'), method: 'delete', confirm: true, type: 'danger' }
+]
+const buttonFields = [{ label: t('common.add'), method: 'add' }]
+let skip = 0
+let limit = inject('limit')
+const total = ref(20)
+// 加载中
+const loading = ref(false)
+const dialog = ref(false)
+const form = ref({})
+// 请求
+onMounted(async () => {
+  loading.value = true
+  await search({ skip, limit })
+  loading.value = false
+})
+const search = async (query = { skip: 0, limit }) => {
+  const info = { skip: query.skip, limit: query.limit, ...searchForm.value }
+  const res = await store.query(info)
+  if (res.errcode == '0') {
+    data.value = res.data.data
+    total.value = res.data.total
+  }
+}
+// 添加
+const toAdd = () => {
+  dialog.value = true
+}
+// 修改
+const toEdit = (data) => {
+  form.value = data
+  dialog.value = true
+}
+// 删除
+const toDelete = async (data) => {
+  const res = await store.del(data._id)
+  if ($checkRes(res, true)) {
+    search({ skip: 0, limit })
+  }
+}
+const toSave = async () => {
+  const data = cloneDeep(form.value)
+  let res
+  if (get(data, '_id')) res = await store.update(data)
+  else res = await store.create({ ...data })
+  if ($checkRes(res, true)) {
+    search({ skip: 0, limit })
+    toClose()
+  }
+}
+// 重置
+const toReset = async () => {
+  searchForm.value = {}
+  await search({ skip, limit })
+}
+const toClose = () => {
+  form.value = {}
+  dialog.value = false
+}
+</script>
+<style scoped lang="scss"></style>

+ 20 - 0
src/views/operate/index.vue

@@ -0,0 +1,20 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one"> 操作日志 </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+// 加载中
+const loading = ref(false)
+// 请求
+onMounted(async () => {
+  loading.value = true
+  loading.value = false
+})
+</script>
+<style scoped lang="scss"></style>

+ 1 - 1
src/views/system/menus/index.vue

@@ -40,7 +40,7 @@ onMounted(async () => {
 })
 })
 const searchOther = async () => {
 const searchOther = async () => {
   const result = await dictDataStore.query({ code: 'icon', is_use: '0' })
   const result = await dictDataStore.query({ code: 'icon', is_use: '0' })
-  if ($checkRes(result)) iconList.value = result.data
+  if ($checkRes(result)) iconList.value = result.data.data
 }
 }
 // #region 接口函数
 // #region 接口函数
 const search = async () => {
 const search = async () => {

+ 11 - 7
src/views/system/menus/parts/menu-table.vue

@@ -3,7 +3,9 @@
     <el-table :data="data" row-key="_id" border>
     <el-table :data="data" row-key="_id" border>
       <el-table-column align="center" label="顺序" sortable prop="order_num" width="80"></el-table-column>
       <el-table-column align="center" label="顺序" sortable prop="order_num" width="80"></el-table-column>
       <el-table-column align="center" label="图标" width="80">
       <el-table-column align="center" label="图标" width="80">
-        <template #default="{ row }"><span :class="['iconfont', row.icon]"></span></template>
+        <template #default="{ row }">
+          <component class="icon" :is="row.icon"></component>
+        </template>
       </el-table-column>
       </el-table-column>
       <el-table-column align="center" label="菜单名称" prop="name"></el-table-column>
       <el-table-column align="center" label="菜单名称" prop="name"></el-table-column>
       <el-table-column align="center" label="路由名称" prop="route_name"></el-table-column>
       <el-table-column align="center" label="路由名称" prop="route_name"></el-table-column>
@@ -23,11 +25,8 @@
       <el-table-column align="center" label="备注" prop="remark" width="100"> </el-table-column>
       <el-table-column align="center" label="备注" prop="remark" width="100"> </el-table-column>
       <el-table-column align="center" :label="$t('common.opera')">
       <el-table-column align="center" :label="$t('common.opera')">
         <template #default="{ row }">
         <template #default="{ row }">
-          <el-link :underline="false" type="primary" size="mini" @click="toUpdate(row)" style="margin-right: 10px">{{
-            $t('common.update') }}</el-link>
-          <el-link :underline="false" type="primary" size="mini" @click="toAddNext(row)" style="margin-right: 10px">
-            添加下一级
-          </el-link>
+          <el-link :underline="false" type="primary" size="mini" @click="toUpdate(row)" style="margin-right: 10px">{{ $t('common.update') }}</el-link>
+          <el-link :underline="false" type="primary" size="mini" @click="toAddNext(row)" style="margin-right: 10px"> 添加下一级 </el-link>
           <el-link v-if="row.is_default !== '0'" :underline="false" type="danger" size="mini" @click="toDelete(row)">
           <el-link v-if="row.is_default !== '0'" :underline="false" type="danger" size="mini" @click="toDelete(row)">
             {{ $t('common.delete') }}
             {{ $t('common.delete') }}
           </el-link>
           </el-link>
@@ -66,4 +65,9 @@ const getStatus = (row) => {
   return word
   return word
 }
 }
 </script>
 </script>
-<style scoped></style>
+<style scoped>
+.icon {
+  width: 16px;
+  height: 16px;
+}
+</style>

+ 20 - 0
src/views/system/organization/index.vue

@@ -0,0 +1,20 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one"> 组织管理 </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+// 加载中
+const loading = ref(false)
+// 请求
+onMounted(async () => {
+  loading.value = true
+  loading.value = false
+})
+</script>
+<style scoped lang="scss"></style>

+ 1 - 2
src/views/user/admin/index.vue

@@ -54,8 +54,7 @@ const fields = [
 ]
 ]
 const opera = [
 const opera = [
   { label: t('common.update'), method: 'edit', display: (i) => i.is_super !== '0' },
   { label: t('common.update'), method: 'edit', display: (i) => i.is_super !== '0' },
-  // { label: t('pages.admin.bind'), method: 'bind' },
-  { label: '重置密码', method: 'rp', type: 'warning', confirm: true, confirmWord: t('pages.admin.rpConfirm') },
+  { label: t('common.resetPwd'), method: 'rp', type: 'warning', confirm: true, confirmWord: t('pages.admin.rpConfirm') },
   {
   {
     label: t('common.is_use_disabled'),
     label: t('common.is_use_disabled'),
     method: 'changeUse',
     method: 'changeUse',