2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 06:47:20 +08:00

feat: alova.js替换axios

This commit is contained in:
耗子
2025-02-09 04:42:44 +08:00
parent a07c50b3f5
commit 23e215b009
14 changed files with 233 additions and 568 deletions

View File

@@ -6,7 +6,7 @@ VITE_PUBLIC_PATH = '/'
# 是否hash路由模式
VITE_USE_HASH = false
# axios base api
# base api
VITE_BASE_API = '/api'
# 是否启用代理(只对本地vite server生效)

View File

@@ -37,7 +37,6 @@
"@xterm/addon-webgl": "^0.18.0",
"@xterm/xterm": "^5.5.0",
"alova": "^3.2.7",
"axios": "^1.7.9",
"cronstrue": "^2.52.0",
"echarts": "^5.6.0",
"install": "^0.13.0",

73
web/pnpm-lock.yaml generated
View File

@@ -50,9 +50,6 @@ importers:
alova:
specifier: ^3.2.7
version: 3.2.8
axios:
specifier: ^1.7.9
version: 1.7.9
cronstrue:
specifier: ^2.52.0
version: 2.54.0
@@ -1595,16 +1592,10 @@ packages:
async@3.2.6:
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
available-typed-arrays@1.0.7:
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
engines: {node: '>= 0.4'}
axios@1.7.9:
resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==}
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
@@ -1728,10 +1719,6 @@ packages:
colorette@2.0.20:
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
commander@13.1.0:
resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==}
engines: {node: '>=18'}
@@ -1891,10 +1878,6 @@ packages:
defu@6.1.4:
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
destr@2.0.3:
resolution: {integrity: sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==}
@@ -2169,15 +2152,6 @@ packages:
flatted@3.3.2:
resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==}
follow-redirects@1.15.9:
resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
for-each@0.3.4:
resolution: {integrity: sha512-kKaIINnFpzW6ffJNDjjyjrk21BkDx38c0xa/klsT8VzLCaMEefv4ZTacrcVR4DmgTeBra++jMDAfS/tS799YDw==}
engines: {node: '>= 0.4'}
@@ -2186,10 +2160,6 @@ packages:
resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==}
engines: {node: '>=14'}
form-data@4.0.1:
resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==}
engines: {node: '>= 6'}
fs-extra@10.1.0:
resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
engines: {node: '>=12'}
@@ -2701,14 +2671,6 @@ packages:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'}
mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
minimatch@10.0.1:
resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==}
engines: {node: 20 || >=22}
@@ -3029,9 +2991,6 @@ packages:
resolution: {integrity: sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==}
engines: {node: '>=18'}
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
punycode.js@2.3.1:
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
engines: {node: '>=6'}
@@ -5359,20 +5318,10 @@ snapshots:
async@3.2.6: {}
asynckit@0.4.0: {}
available-typed-arrays@1.0.7:
dependencies:
possible-typed-array-names: 1.0.0
axios@1.7.9:
dependencies:
follow-redirects: 1.15.9
form-data: 4.0.1
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
balanced-match@1.0.2: {}
binary-extensions@2.3.0: {}
@@ -5515,10 +5464,6 @@ snapshots:
colorette@2.0.20: {}
combined-stream@1.0.8:
dependencies:
delayed-stream: 1.0.0
commander@13.1.0: {}
commander@2.20.3: {}
@@ -5673,8 +5618,6 @@ snapshots:
defu@6.1.4: {}
delayed-stream@1.0.0: {}
destr@2.0.3: {}
detect-libc@1.0.3:
@@ -6075,8 +6018,6 @@ snapshots:
flatted@3.3.2: {}
follow-redirects@1.15.9: {}
for-each@0.3.4:
dependencies:
is-callable: 1.2.7
@@ -6086,12 +6027,6 @@ snapshots:
cross-spawn: 7.0.6
signal-exit: 4.1.0
form-data@4.0.1:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.35
fs-extra@10.1.0:
dependencies:
graceful-fs: 4.2.11
@@ -6596,12 +6531,6 @@ snapshots:
braces: 3.0.3
picomatch: 2.3.1
mime-db@1.52.0: {}
mime-types@2.1.35:
dependencies:
mime-db: 1.52.0
minimatch@10.0.1:
dependencies:
brace-expansion: 2.0.1
@@ -6916,8 +6845,6 @@ snapshots:
dependencies:
parse-ms: 4.0.0
proxy-from-env@1.1.0: {}
punycode.js@2.3.1: {}
punycode@2.3.1: {}

View File

@@ -1,57 +1,57 @@
import { request } from '@/utils'
import { http } from '@/utils'
export default {
// 获取容器列表
containerList: (page: number, limit: number): any =>
request.get('/container/container', { params: { page, limit } }),
http.Get('/container/container', { params: { page, limit } }),
// 添加容器
containerCreate: (config: any): any => request.post('/container/container', config),
containerCreate: (config: any): any => http.Post('/container/container', config),
// 删除容器
containerRemove: (id: string): any => request.delete(`/container/container/${id}`),
containerRemove: (id: string): any => http.Delete(`/container/container/${id}`),
// 启动容器
containerStart: (id: string): any => request.post(`/container/container/${id}/start`),
containerStart: (id: string): any => http.Post(`/container/container/${id}/start`),
// 停止容器
containerStop: (id: string): any => request.post(`/container/container/${id}/stop`),
containerStop: (id: string): any => http.Post(`/container/container/${id}/stop`),
// 重启容器
containerRestart: (id: string): any => request.post(`/container/container/${id}/restart`),
containerRestart: (id: string): any => http.Post(`/container/container/${id}/restart`),
// 暂停容器
containerPause: (id: string): any => request.post(`/container/container/${id}/pause`),
containerPause: (id: string): any => http.Post(`/container/container/${id}/pause`),
// 恢复容器
containerUnpause: (id: string): any => request.post(`/container/container/${id}/unpause`),
containerUnpause: (id: string): any => http.Post(`/container/container/${id}/unpause`),
// 杀死容器
containerKill: (id: string): any => request.post(`/container/container/${id}/kill`),
containerKill: (id: string): any => http.Post(`/container/container/${id}/kill`),
// 重命名容器
containerRename: (id: string, name: string): any =>
request.post(`/container/container/${id}/rename`, { name }),
http.Post(`/container/container/${id}/rename`, { name }),
// 获取容器日志
containerLogs: (id: string): any => request.get(`/container/container/${id}/logs`),
containerLogs: (id: string): any => http.Get(`/container/container/${id}/logs`),
// 清理容器
containerPrune: (): any => request.post(`/container/container/prune`),
containerPrune: (): any => http.Post(`/container/container/prune`),
// 获取网络列表
networkList: (page: number, limit: number): any =>
request.get(`/container/network`, { params: { page, limit } }),
http.Get(`/container/network`, { params: { page, limit } }),
// 创建网络
networkCreate: (config: any): any => request.post(`/container/network`, config),
networkCreate: (config: any): any => http.Post(`/container/network`, config),
// 删除网络
networkRemove: (id: string): any => request.delete(`/container/network/${id}`),
networkRemove: (id: string): any => http.Delete(`/container/network/${id}`),
// 清理网络
networkPrune: (): any => request.post(`/container/network/prune`),
networkPrune: (): any => http.Post(`/container/network/prune`),
// 获取镜像列表
imageList: (page: number, limit: number): any =>
request.get(`/container/image`, { params: { page, limit } }),
http.Get(`/container/image`, { params: { page, limit } }),
// 拉取镜像
imagePull: (config: any): any => request.post(`/container/image`, config),
imagePull: (config: any): any => http.Post(`/container/image`, config),
// 删除镜像
imageRemove: (id: string): any => request.delete(`/container/image/${id}`),
imageRemove: (id: string): any => http.Delete(`/container/image/${id}`),
// 清理镜像
imagePrune: (): any => request.post(`/container/image/prune`),
imagePrune: (): any => http.Post(`/container/image/prune`),
// 获取卷列表
volumeList: (page: number, limit: number): any =>
request.get(`/container/volume`, { params: { page, limit } }),
http.Get(`/container/volume`, { params: { page, limit } }),
// 创建卷
volumeCreate: (config: any): any => request.post(`/container/volume`, config),
volumeCreate: (config: any): any => http.Post(`/container/volume`, config),
// 删除卷
volumeRemove: (id: string): any => request.delete(`/container/volume/${id}`),
volumeRemove: (id: string): any => http.Delete(`/container/volume/${id}`),
// 清理卷
volumePrune: (): any => request.post(`/container/volume/prune`)
volumePrune: (): any => http.Post(`/container/volume/prune`)
}

View File

@@ -1,18 +1,4 @@
import { useUserStore } from '@/store'
import type { ErrorResolveResponse } from '~/types/axios'
/** 自定义错误 */
export class AxiosRejectError extends Error {
code?: number | string
data?: any
constructor(rejectData: ErrorResolveResponse, options?: ErrorOptions) {
const { code, message, data } = rejectData
super(message, options)
this.code = code
this.data = data
}
}
export function resolveResError(code: number | string | undefined, message = ''): string {
switch (code) {

View File

@@ -3,26 +3,6 @@ import type { AlovaXHRResponse } from '@alova/adapter-xhr'
import { xhrRequestAdapter } from '@alova/adapter-xhr'
import { createAlova, Method } from 'alova'
import VueHook from 'alova/vue'
import axios from 'axios'
import { reqReject, reqResolve, resReject, resResolve } from './interceptors'
export function createAxios(options = {}) {
const defaultOptions = {
adapter: 'fetch',
timeout: 0
}
const service = axios.create({
...defaultOptions,
...options
})
service.interceptors.request.use(reqResolve, reqReject)
service.interceptors.response.use(resResolve, resReject)
return service
}
export const request = createAxios({
baseURL: import.meta.env.VITE_BASE_API
})
export const http = createAlova({
id: 'panel',

View File

@@ -1,85 +0,0 @@
import type { AxiosError, AxiosResponse } from 'axios'
import type { RequestConfig } from '~/types/axios'
import { AxiosRejectError, resolveResError } from './helpers'
/** 请求拦截 */
export function reqResolve(config: RequestConfig) {
return config
}
/** 请求错误拦截 */
export function reqReject(error: AxiosError) {
return Promise.reject(error)
}
/** 响应拦截 */
export function resResolve(response: AxiosResponse) {
const { data, status, config, statusText } = response
if (status !== 200) {
const code = data?.code ?? status
const message = resolveResError(code, data?.message ?? statusText)
const { noNeedTip } = config as RequestConfig
if (!noNeedTip) {
if (code == 422) {
window.$message.error(message)
} else {
if (code != 401) {
window.$dialog.error({
title: '请求返回异常',
content: message,
maskClosable: false
})
}
}
}
return Promise.reject(new AxiosRejectError({ code, message, data: data || response }))
}
return Promise.resolve(data)
}
/** 响应错误拦截 */
export function resReject(error: AxiosError) {
if (!error || !error.response) {
const code = error?.code
/** 根据code处理对应的操作并返回处理后的message */
const message = resolveResError(code, error.message)
window.$dialog.error({
title: '请求出现异常',
content: message,
maskClosable: false
})
return Promise.reject(new AxiosRejectError({ code, message, data: error }))
}
const { data, status, config } = error.response
let { code, message } = data as AxiosRejectError
code = code ?? status
message = message ?? error.message
message = resolveResError(code, message)
/** 需要错误提醒 */
const { noNeedTip } = config as RequestConfig
if (!noNeedTip) {
if (code == 422) {
window.$message.error(message)
} else {
if (code != 401) {
window.$dialog.error({
title: '请求返回异常',
content: message,
maskClosable: false
})
}
}
}
return Promise.reject(
new AxiosRejectError({
code,
message,
data: error.response?.data || error.response
})
)
}

View File

@@ -82,31 +82,28 @@ const removeVolumeRow = (index: number) => {
createModel.volumes.splice(index, 1)
}
const getNetworks = async () => {
const { data } = await container.networkList(1, 1000)
networks.value = data.items.map((item: any) => {
return {
label: item.name,
value: item.id
const getNetworks = () => {
useRequest(container.networkList(1, 1000)).onSuccess(({ data }) => {
networks.value = data.items.map((item: any) => {
return {
label: item.name,
value: item.id
}
})
if (networks.value.length > 0) {
createModel.network = networks.value[0].value
}
})
if (networks.value.length > 0) {
createModel.network = networks.value[0].value
}
}
const handleSubmit = () => {
doSubmit.value = true
container
.containerCreate(createModel)
.then(() => {
useRequest(container.containerCreate(createModel))
.onSuccess(() => {
window.$message.success('创建成功')
handleClose()
})
.catch(() => {
window.$message.error('创建失败')
})
.finally(() => {
.onComplete(() => {
doSubmit.value = false
})
}

View File

@@ -4,9 +4,6 @@ import { NButton, NDataTable, NDropdown, NFlex, NInput, NSwitch, NTag } from 'na
import container from '@/api/panel/container'
import ContainerCreate from '@/views/container/ContainerCreate.vue'
import type { ContainerList } from '@/views/container/types'
const data = ref<ContainerList[]>([] as ContainerList[])
const logModal = ref(false)
const logs = ref('')
@@ -209,103 +206,86 @@ const columns: any = [
}
]
const pagination = reactive({
page: 1,
pageCount: 1,
pageSize: 20,
itemCount: 0,
showQuickJumper: true,
showSizePicker: true,
pageSizes: [20, 50, 100, 200]
})
const onPageChange = (page: number) => {
pagination.page = page
getContainerList(page, pagination.pageSize).then((res) => {
data.value = res.items
pagination.itemCount = res.total
pagination.pageCount = res.total / pagination.pageSize + 1
})
}
const onPageSizeChange = (pageSize: number) => {
pagination.pageSize = pageSize
onPageChange(1)
}
const getContainerList = async (page: number, pageSize: number) => {
const { data } = await container.containerList(page, pageSize)
return data
}
const { loading, data, page, total, pageSize, pageCount, refresh } = usePagination(
(page, pageSize) => container.containerList(page, pageSize),
{
initialData: { total: 0, list: [] },
initialPageSize: 20,
total: (res: any) => res.total,
data: (res: any) => res.items
}
)
const handleShowLog = async (row: any) => {
container.containerLogs(row.id).then((res) => {
logs.value = res.data
useRequest(container.containerLogs(row.id)).onSuccess(({ data }) => {
logs.value = data
logModal.value = true
})
}
const handleRename = () => {
container.containerRename(renameModel.value.id, renameModel.value.name).then(() => {
window.$message.success('重命名成功')
renameModal.value = false
onPageChange(pagination.page)
})
useRequest(container.containerRename(renameModel.value.id, renameModel.value.name)).onSuccess(
() => {
refresh()
renameModal.value = false
window.$message.success('重命名成功')
}
)
}
const handleStart = (id: string) => {
container.containerStart(id).then(() => {
useRequest(container.containerStart(id)).onSuccess(() => {
refresh()
window.$message.success('启动成功')
onPageChange(pagination.page)
})
}
const handleStop = (id: string) => {
container.containerStop(id).then(() => {
useRequest(container.containerStop(id)).onSuccess(() => {
refresh()
window.$message.success('停止成功')
onPageChange(pagination.page)
})
}
const handleRestart = (id: string) => {
container.containerRestart(id).then(() => {
useRequest(container.containerRestart(id)).onSuccess(() => {
refresh()
window.$message.success('重启成功')
onPageChange(pagination.page)
})
}
const handleForceStop = (id: string) => {
container.containerKill(id).then(() => {
useRequest(container.containerKill(id)).onSuccess(() => {
refresh()
window.$message.success('强制停止成功')
onPageChange(pagination.page)
})
}
const handlePause = (id: string) => {
container.containerPause(id).then(() => {
useRequest(container.containerPause(id)).onSuccess(() => {
refresh()
window.$message.success('暂停成功')
onPageChange(pagination.page)
})
}
const handleUnpause = (id: string) => {
container.containerUnpause(id).then(() => {
useRequest(container.containerUnpause(id)).onSuccess(() => {
refresh()
window.$message.success('恢复成功')
onPageChange(pagination.page)
})
}
const handleDelete = (id: string) => {
container.containerRemove(id).then(() => {
useRequest(container.containerRemove(id)).onSuccess(() => {
refresh()
window.$message.success('删除成功')
onPageChange(pagination.page)
})
}
const handlePrune = () => {
container.containerPrune().then(() => {
useRequest(container.containerPrune()).onSuccess(() => {
refresh()
window.$message.success('清理成功')
onPageChange(pagination.page)
})
}
@@ -315,14 +295,17 @@ const bulkStart = async () => {
return
}
for (const id of selectedRowKeys.value) {
await container.containerStart(id).then(() => {
const container = data.value.find((item) => item.id === id)
const promises = selectedRowKeys.value.map((id: any) =>
useRequest(container.containerStart(id)).onSuccess(() => {
const container = data.value.find((item: any) => item.id === id)
window.$message.success(`${container?.name} 启动成功`)
})
}
)
onPageChange(pagination.page)
await Promise.all(promises)
selectedRowKeys.value = []
await refresh()
}
const bulkStop = async () => {
@@ -331,14 +314,17 @@ const bulkStop = async () => {
return
}
for (const id of selectedRowKeys.value) {
await container.containerStop(id).then(() => {
const container = data.value.find((item) => item.id === id)
const promises = selectedRowKeys.value.map((id: any) =>
useRequest(container.containerStop(id)).onSuccess(() => {
const container = data.value.find((item: any) => item.id === id)
window.$message.success(`${container?.name} 停止成功`)
})
}
)
onPageChange(pagination.page)
await Promise.all(promises)
selectedRowKeys.value = []
await refresh()
}
const bulkRestart = async () => {
@@ -347,14 +333,17 @@ const bulkRestart = async () => {
return
}
for (const id of selectedRowKeys.value) {
await container.containerRestart(id).then(() => {
const container = data.value.find((item) => item.id === id)
const promises = selectedRowKeys.value.map((id: any) =>
useRequest(container.containerRestart(id)).onSuccess(() => {
const container = data.value.find((item: any) => item.id === id)
window.$message.success(`${container?.name} 重启成功`)
})
}
)
onPageChange(pagination.page)
await Promise.all(promises)
selectedRowKeys.value = []
await refresh()
}
const bulkForceStop = async () => {
@@ -363,14 +352,17 @@ const bulkForceStop = async () => {
return
}
for (const id of selectedRowKeys.value) {
await container.containerKill(id).then(() => {
const container = data.value.find((item) => item.id === id)
const promises = selectedRowKeys.value.map((id: any) =>
useRequest(container.containerKill(id)).onSuccess(() => {
const container = data.value.find((item: any) => item.id === id)
window.$message.success(`${container?.name} 强制停止成功`)
})
}
)
onPageChange(pagination.page)
await Promise.all(promises)
selectedRowKeys.value = []
await refresh()
}
const bulkDelete = async () => {
@@ -379,14 +371,17 @@ const bulkDelete = async () => {
return
}
for (const id of selectedRowKeys.value) {
await container.containerRemove(id).then(() => {
const container = data.value.find((item) => item.id === id)
const promises = selectedRowKeys.value.map((id: any) =>
useRequest(container.containerRemove(id)).onSuccess(() => {
const container = data.value.find((item: any) => item.id === id)
window.$message.success(`${container?.name} 删除成功`)
})
}
)
onPageChange(pagination.page)
await Promise.all(promises)
selectedRowKeys.value = []
await refresh()
}
const bulkPause = async () => {
@@ -395,14 +390,17 @@ const bulkPause = async () => {
return
}
for (const id of selectedRowKeys.value) {
await container.containerPause(id).then(() => {
const container = data.value.find((item) => item.id === id)
const promises = selectedRowKeys.value.map((id: any) =>
useRequest(container.containerPause(id)).onSuccess(() => {
const container = data.value.find((item: any) => item.id === id)
window.$message.success(`${container?.name} 暂停成功`)
})
}
)
onPageChange(pagination.page)
await Promise.all(promises)
selectedRowKeys.value = []
await refresh()
}
const bulkUnpause = async () => {
@@ -411,23 +409,26 @@ const bulkUnpause = async () => {
return
}
for (const id of selectedRowKeys.value) {
await container.containerUnpause(id).then(() => {
const container = data.value.find((item) => item.id === id)
const promises = selectedRowKeys.value.map((id: any) =>
useRequest(container.containerUnpause(id)).onSuccess(() => {
const container = data.value.find((item: any) => item.id === id)
window.$message.success(`${container?.name} 恢复成功`)
})
}
)
onPageChange(pagination.page)
await Promise.all(promises)
selectedRowKeys.value = []
await refresh()
}
const closeContainerCreateModal = () => {
containerCreateModal.value = false
onPageChange(pagination.page)
refresh()
}
onMounted(() => {
onPageChange(pagination.page)
refresh()
})
</script>
@@ -452,16 +453,23 @@ onMounted(() => {
<n-data-table
striped
remote
:loading="loading"
:scroll-x="1000"
:data="data"
:columns="columns"
:row-key="(row: any) => row.id"
:pagination="pagination"
:bordered="false"
:loading="false"
@update:page="onPageChange"
@update:page-size="onPageSizeChange"
@update:checked-row-keys="onChecked"
v-model:page="page"
v-model:pageSize="pageSize"
:pagination="{
page: page,
pageCount: pageCount,
pageSize: pageSize,
itemCount: total,
showQuickJumper: true,
showSizePicker: true,
pageSizes: [20, 50, 100, 200]
}"
/>
</n-card>
</n-space>

View File

@@ -3,7 +3,6 @@ import { NButton, NDataTable, NFlex, NInput, NPopconfirm, NTag } from 'naive-ui'
import container from '@/api/panel/container'
import { formatDateTime } from '@/utils'
import type { ImageList } from '@/views/container/types'
const pullModel = ref({
name: '',
@@ -12,9 +11,6 @@ const pullModel = ref({
password: ''
})
const pullModal = ref(false)
const loading = ref(false)
const data = ref<ImageList[]>([] as ImageList[])
const selectedRowKeys = ref<any>([])
const onChecked = (rowKeys: any) => {
@@ -108,65 +104,45 @@ const columns: any = [
}
]
const pagination = reactive({
page: 1,
pageCount: 1,
pageSize: 20,
itemCount: 0,
showQuickJumper: true,
showSizePicker: true,
pageSizes: [20, 50, 100, 200]
})
const onPageChange = (page: number) => {
pagination.page = page
getImageList(page, pagination.pageSize).then((res) => {
data.value = res.items
pagination.itemCount = res.total
pagination.pageCount = res.total / pagination.pageSize + 1
})
}
const onPageSizeChange = (pageSize: number) => {
pagination.pageSize = pageSize
onPageChange(1)
}
const getImageList = async (page: number, pageSize: number) => {
const { data } = await container.imageList(page, pageSize)
return data
}
const { loading, data, page, total, pageSize, pageCount, refresh } = usePagination(
(page, pageSize) => container.imageList(page, pageSize),
{
initialData: { total: 0, list: [] },
initialPageSize: 20,
total: (res: any) => res.total,
data: (res: any) => res.items
}
)
const handleDelete = async (row: any) => {
container.imageRemove(row.id).then(() => {
useRequest(container.imageRemove(row.id)).onSuccess(() => {
refresh()
window.$message.success('删除成功')
onPageChange(pagination.page)
})
}
const handlePrune = () => {
container.imagePrune().then(() => {
useRequest(container.imagePrune()).onSuccess(() => {
refresh()
window.$message.success('清理成功')
onPageChange(pagination.page)
})
}
const handlePull = () => {
loading.value = true
container
.imagePull(pullModel.value)
.then(() => {
useRequest(container.imagePull(pullModel.value))
.onSuccess(() => {
refresh()
window.$message.success('拉取成功')
onPageChange(pagination.page)
})
.finally(() => {
.onComplete(() => {
loading.value = false
pullModal.value = false
})
}
onMounted(() => {
onPageChange(pagination.page)
refresh()
})
</script>
@@ -182,16 +158,23 @@ onMounted(() => {
<n-data-table
striped
remote
:loading="loading"
:scroll-x="1000"
:data="data"
:columns="columns"
:row-key="(row: any) => row.id"
:pagination="pagination"
:bordered="false"
:loading="false"
@update:page="onPageChange"
@update:page-size="onPageSizeChange"
@update:checked-row-keys="onChecked"
v-model:page="page"
v-model:pageSize="pageSize"
:pagination="{
page: page,
pageCount: pageCount,
pageSize: pageSize,
itemCount: total,
showQuickJumper: true,
showSizePicker: true,
pageSizes: [20, 50, 100, 200]
}"
/>
</n-card>
</n-space>

View File

@@ -3,7 +3,6 @@ import { NButton, NDataTable, NFlex, NInput, NPopconfirm, NTag } from 'naive-ui'
import container from '@/api/panel/container'
import { formatDateTime } from '@/utils'
import type { NetworkList } from '@/views/container/types'
const createModel = ref({
name: '',
@@ -34,9 +33,7 @@ const options = [
]
const createModal = ref(false)
const loading = ref(false)
const data = ref<NetworkList[]>([] as NetworkList[])
const selectedRowKeys = ref<any>([])
const onChecked = (rowKeys: any) => {
@@ -147,65 +144,44 @@ const columns: any = [
}
]
const pagination = reactive({
page: 1,
pageCount: 1,
pageSize: 20,
itemCount: 0,
showQuickJumper: true,
showSizePicker: true,
pageSizes: [20, 50, 100, 200]
})
const { loading, data, page, total, pageSize, pageCount, refresh } = usePagination(
(page, pageSize) => container.networkList(page, pageSize),
{
initialData: { total: 0, list: [] },
initialPageSize: 20,
total: (res: any) => res.total,
data: (res: any) => res.items
}
)
const onPageChange = (page: number) => {
pagination.page = page
getNetworkList(page, pagination.pageSize).then((res) => {
data.value = res.items
pagination.itemCount = res.total
pagination.pageCount = res.total / pagination.pageSize + 1
})
}
const onPageSizeChange = (pageSize: number) => {
pagination.pageSize = pageSize
onPageChange(1)
}
const getNetworkList = async (page: number, pageSize: number) => {
const { data } = await container.networkList(page, pageSize)
return data
}
const handleDelete = async (row: any) => {
container.networkRemove(row.id).then(() => {
const handleDelete = (row: any) => {
useRequest(container.networkRemove(row.id)).onSuccess(() => {
window.$message.success('删除成功')
onPageChange(pagination.page)
})
}
const handlePrune = () => {
container.networkPrune().then(() => {
useRequest(container.networkPrune()).onSuccess(() => {
refresh()
window.$message.success('清理成功')
onPageChange(pagination.page)
})
}
const handleCreate = () => {
loading.value = true
container
.networkCreate(createModel.value)
.then(() => {
useRequest(container.networkCreate(createModel.value))
.onSuccess(() => {
refresh()
window.$message.success('创建成功')
onPageChange(pagination.page)
})
.finally(() => {
.onComplete(() => {
loading.value = false
createModal.value = false
})
}
onMounted(() => {
onPageChange(pagination.page)
refresh()
})
</script>
@@ -221,16 +197,23 @@ onMounted(() => {
<n-data-table
striped
remote
:loading="loading"
:scroll-x="1000"
:data="data"
:columns="columns"
:row-key="(row: any) => row.id"
:pagination="pagination"
:bordered="false"
:loading="false"
@update:page="onPageChange"
@update:page-size="onPageSizeChange"
@update:checked-row-keys="onChecked"
v-model:page="page"
v-model:pageSize="pageSize"
:pagination="{
page: page,
pageCount: pageCount,
pageSize: pageSize,
itemCount: total,
showQuickJumper: true,
showSizePicker: true,
pageSizes: [20, 50, 100, 200]
}"
/>
</n-card>
</n-space>

View File

@@ -3,7 +3,6 @@ import { NButton, NDataTable, NInput, NPopconfirm } from 'naive-ui'
import container from '@/api/panel/container'
import { formatDateTime } from '@/utils'
import type { VolumeList } from '@/views/container/types'
const createModel = ref({
name: '',
@@ -15,9 +14,7 @@ const createModel = ref({
const options = [{ label: 'local', value: 'local' }]
const createModal = ref(false)
const loading = ref(false)
const data = ref<VolumeList[]>([] as VolumeList[])
const selectedRowKeys = ref<any>([])
const onChecked = (rowKeys: any) => {
@@ -101,65 +98,45 @@ const columns: any = [
}
]
const pagination = reactive({
page: 1,
pageCount: 1,
pageSize: 20,
itemCount: 0,
showQuickJumper: true,
showSizePicker: true,
pageSizes: [20, 50, 100, 200]
})
const onPageChange = (page: number) => {
pagination.page = page
getVolumeList(page, pagination.pageSize).then((res) => {
data.value = res.items
pagination.itemCount = res.total
pagination.pageCount = res.total / pagination.pageSize + 1
})
}
const onPageSizeChange = (pageSize: number) => {
pagination.pageSize = pageSize
onPageChange(1)
}
const getVolumeList = async (page: number, pageSize: number) => {
const { data } = await container.volumeList(page, pageSize)
return data
}
const { loading, data, page, total, pageSize, pageCount, refresh } = usePagination(
(page, pageSize) => container.volumeList(page, pageSize),
{
initialData: { total: 0, list: [] },
initialPageSize: 20,
total: (res: any) => res.total,
data: (res: any) => res.items
}
)
const handleDelete = async (row: any) => {
container.volumeRemove(row.id).then(() => {
useRequest(container.volumeRemove(row.id)).onSuccess(() => {
refresh()
window.$message.success('删除成功')
onPageChange(pagination.page)
})
}
const handlePrune = () => {
container.volumePrune().then(() => {
useRequest(container.volumePrune()).onSuccess(() => {
refresh()
window.$message.success('清理成功')
onPageChange(pagination.page)
})
}
const handleCreate = () => {
loading.value = true
container
.volumeCreate(createModel.value)
.then(() => {
useRequest(container.volumeCreate(createModel.value))
.onSuccess(() => {
refresh()
window.$message.success('创建成功')
onPageChange(pagination.page)
})
.finally(() => {
.onComplete(() => {
loading.value = false
createModal.value = false
})
}
onMounted(() => {
onPageChange(pagination.page)
refresh()
})
</script>
@@ -175,16 +152,23 @@ onMounted(() => {
<n-data-table
striped
remote
:loading="loading"
:scroll-x="1000"
:data="data"
:columns="columns"
:row-key="(row: any) => row.id"
:pagination="pagination"
:bordered="false"
:loading="false"
@update:page="onPageChange"
@update:page-size="onPageSizeChange"
@update:checked-row-keys="onChecked"
v-model:page="page"
v-model:pageSize="pageSize"
:pagination="{
page: page,
pageCount: pageCount,
pageSize: pageSize,
itemCount: total,
showQuickJumper: true,
showSizePicker: true,
pageSizes: [20, 50, 100, 200]
}"
/>
</n-card>
</n-space>

View File

@@ -1,85 +0,0 @@
export interface ContainerList {
command: string
created: string
id: string
image: string
image_id: string
labels: {
[key: string]: string
}
name: string
ports: [
{
IP: string
PrivatePort: number
PublicPort: number
Type: string
}
]
state: string
status: string
}
export interface ImageList {
id: string
created: string
containers: number
size: string
labels: {
[key: string]: string
}
repo_tags: string[]
repo_digests: string[]
}
export interface NetworkList {
id: string
name: string
driver: string
ipv6: boolean
scope: string
internal: boolean
attachable: boolean
ingress: boolean
labels: {
[key: string]: string
}
options: {
[key: string]: string
}
ipam: {
driver: string
config: {
subnet: string
gateway: string
ip_range: string
aux_address: {
[key: string]: string
}
}[]
options: {
[key: string]: string
}
}
}
export interface VolumeList {
id: string
created: string
driver: string
mount: string
labels: {
[key: string]: string
}
options: {
[key: string]: string
}
scope: string
status: {
[key: string]: string
}
usage: {
ref_count: number
size: string
}
}

12
web/types/axios.d.ts vendored
View File

@@ -1,12 +0,0 @@
import type { InternalAxiosRequestConfig } from 'axios'
interface RequestConfig extends InternalAxiosRequestConfig {
/** 接口是否需要错误提醒 */
noNeedTip?: boolean
}
interface ErrorResolveResponse {
code?: number | string
message: string
data?: any
}