From 1356f91b9de86dfc78460533146ab6ccc4117af3 Mon Sep 17 00:00:00 2001 From: dailz Date: Thu, 16 Apr 2026 22:45:23 +0800 Subject: [PATCH] feat(web): add API client, router, and app layout Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- web/src/App.vue | 39 +++++++++++++++++++++++++++++++++++++++ web/src/api/client.ts | 24 ++++++++++++++++++++++++ web/src/api/jobs.ts | 22 ++++++++++++++++++++++ web/src/main.ts | 6 ++++++ web/src/router/index.ts | 41 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 132 insertions(+) create mode 100644 web/src/App.vue create mode 100644 web/src/api/client.ts create mode 100644 web/src/api/jobs.ts create mode 100644 web/src/main.ts create mode 100644 web/src/router/index.ts diff --git a/web/src/App.vue b/web/src/App.vue new file mode 100644 index 0000000..ec9e6ae --- /dev/null +++ b/web/src/App.vue @@ -0,0 +1,39 @@ + + + diff --git a/web/src/api/client.ts b/web/src/api/client.ts new file mode 100644 index 0000000..a892414 --- /dev/null +++ b/web/src/api/client.ts @@ -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 + ElMessage.error(apiError.error || '请求失败') + } else { + ElMessage.error('无法连接到后端服务') + } + return Promise.reject(error) + } +) + +export default apiClient diff --git a/web/src/api/jobs.ts b/web/src/api/jobs.ts new file mode 100644 index 0000000..0a05300 --- /dev/null +++ b/web/src/api/jobs.ts @@ -0,0 +1,22 @@ +import apiClient from './client' +import type { ApiResponse, SubmitJobRequest, JobResponse, JobListResponse, JobHistoryParams } from '@/types/jobs' + +export function submitJob(data: SubmitJobRequest): Promise> { + return apiClient.post('/jobs/submit', data) +} + +export function getJobs(params?: { page?: number; page_size?: number }): Promise> { + return apiClient.get('/jobs', { params }) +} + +export function getJobHistory(params?: JobHistoryParams): Promise> { + return apiClient.get('/jobs/history', { params }) +} + +export function getJob(id: string): Promise> { + return apiClient.get(`/jobs/${id}`) +} + +export function cancelJob(id: string): Promise> { + return apiClient.delete(`/jobs/${id}`) +} diff --git a/web/src/main.ts b/web/src/main.ts new file mode 100644 index 0000000..7e0fdcf --- /dev/null +++ b/web/src/main.ts @@ -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') diff --git a/web/src/router/index.ts b/web/src/router/index.ts new file mode 100644 index 0000000..5150b49 --- /dev/null +++ b/web/src/router/index.ts @@ -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