feat(web): add API client, router, and app layout
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
39
web/src/App.vue
Normal file
39
web/src/App.vue
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<template>
|
||||||
|
<el-config-provider :locale="zhCn">
|
||||||
|
<el-container style="height: 100vh">
|
||||||
|
<el-aside width="200px" style="border-right: 1px solid #e6e6e6">
|
||||||
|
<div style="padding: 16px; font-size: 16px; font-weight: 600; text-align: center">
|
||||||
|
HPC 集群管理
|
||||||
|
</div>
|
||||||
|
<el-menu :router="true" :default-active="route.path">
|
||||||
|
<el-menu-item index="/jobs">
|
||||||
|
<el-icon><List /></el-icon>
|
||||||
|
<span>任务列表</span>
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item index="/jobs/history">
|
||||||
|
<el-icon><Timer /></el-icon>
|
||||||
|
<span>任务历史</span>
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item index="/jobs/submit">
|
||||||
|
<el-icon><CirclePlus /></el-icon>
|
||||||
|
<span>提交任务</span>
|
||||||
|
</el-menu-item>
|
||||||
|
</el-menu>
|
||||||
|
</el-aside>
|
||||||
|
<el-main>
|
||||||
|
<router-view />
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
</el-config-provider>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||||
|
import { List, Timer, CirclePlus } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
document.title = 'HPC 集群管理'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
24
web/src/api/client.ts
Normal file
24
web/src/api/client.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import type { ApiResponse } from '@/types/jobs'
|
||||||
|
|
||||||
|
const apiClient = axios.create({
|
||||||
|
baseURL: '/api/v1',
|
||||||
|
})
|
||||||
|
|
||||||
|
apiClient.interceptors.response.use(
|
||||||
|
(response) => {
|
||||||
|
return response.data
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
if (error.response?.data) {
|
||||||
|
const apiError = error.response.data as ApiResponse<unknown>
|
||||||
|
ElMessage.error(apiError.error || '请求失败')
|
||||||
|
} else {
|
||||||
|
ElMessage.error('无法连接到后端服务')
|
||||||
|
}
|
||||||
|
return Promise.reject(error)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export default apiClient
|
||||||
22
web/src/api/jobs.ts
Normal file
22
web/src/api/jobs.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import apiClient from './client'
|
||||||
|
import type { ApiResponse, SubmitJobRequest, JobResponse, JobListResponse, JobHistoryParams } from '@/types/jobs'
|
||||||
|
|
||||||
|
export function submitJob(data: SubmitJobRequest): Promise<ApiResponse<JobResponse>> {
|
||||||
|
return apiClient.post('/jobs/submit', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getJobs(params?: { page?: number; page_size?: number }): Promise<ApiResponse<JobListResponse>> {
|
||||||
|
return apiClient.get('/jobs', { params })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getJobHistory(params?: JobHistoryParams): Promise<ApiResponse<JobListResponse>> {
|
||||||
|
return apiClient.get('/jobs/history', { params })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getJob(id: string): Promise<ApiResponse<JobResponse>> {
|
||||||
|
return apiClient.get(`/jobs/${id}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cancelJob(id: string): Promise<ApiResponse<{ message: string }>> {
|
||||||
|
return apiClient.delete(`/jobs/${id}`)
|
||||||
|
}
|
||||||
6
web/src/main.ts
Normal file
6
web/src/main.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { createApp } from 'vue'
|
||||||
|
import 'element-plus/dist/index.css'
|
||||||
|
import App from './App.vue'
|
||||||
|
import router from './router'
|
||||||
|
|
||||||
|
createApp(App).use(router).mount('#app')
|
||||||
41
web/src/router/index.ts
Normal file
41
web/src/router/index.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHashHistory(),
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
redirect: '/jobs',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/jobs',
|
||||||
|
name: 'JobsList',
|
||||||
|
component: () => import('@/views/Jobs/List.vue'),
|
||||||
|
meta: { title: '任务列表' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/jobs/history',
|
||||||
|
name: 'JobsHistory',
|
||||||
|
component: () => import('@/views/Jobs/History.vue'),
|
||||||
|
meta: { title: '任务历史' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/jobs/submit',
|
||||||
|
name: 'JobsSubmit',
|
||||||
|
component: () => import('@/views/Jobs/Submit.vue'),
|
||||||
|
meta: { title: '提交任务' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/jobs/:id',
|
||||||
|
name: 'JobsDetail',
|
||||||
|
component: () => import('@/views/Jobs/Detail.vue'),
|
||||||
|
meta: { title: '任务详情' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/:pathMatch(.*)*',
|
||||||
|
redirect: '/jobs',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router
|
||||||
Reference in New Issue
Block a user