2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 07:57:21 +08:00

feat: alova.js替换axios

This commit is contained in:
耗子
2025-02-09 03:09:09 +08:00
parent 6ac5e63684
commit 9956824d54
16 changed files with 241 additions and 208 deletions

View File

@@ -23,6 +23,7 @@
"gen-auto-import": "tsx gen-auto-import.ts"
},
"dependencies": {
"@alova/adapter-xhr": "^2.1.1",
"@eslint/eslintrc": "^3.2.0",
"@fontsource-variable/jetbrains-mono": "^5.1.1",
"@guolao/vue-monaco-editor": "^1.5.4",

29
web/pnpm-lock.yaml generated
View File

@@ -8,6 +8,9 @@ importers:
.:
dependencies:
'@alova/adapter-xhr':
specifier: ^2.1.1
version: 2.1.1(alova@3.2.8)
'@eslint/eslintrc':
specifier: ^3.2.0
version: 3.2.0
@@ -207,6 +210,11 @@ importers:
packages:
'@alova/adapter-xhr@2.1.1':
resolution: {integrity: sha512-053tY4wVEL5PUX8HwvFrp/y1wTObGjMvwVBLUVSOcZKuZwcoUraWdQoWAdNRnSWfwJoPEd+ta9EdS4KPqTcz9g==}
peerDependencies:
alova: ^3.0.20
'@alova/shared@1.1.2':
resolution: {integrity: sha512-8q/gMHFpzm7XYcaUlsyTCMDRRhFnewwheTeObMjPl1+bFdr+wZuBEHEPYIyd8tyzLwfrqpBeonaMN2tlngM8EA==}
@@ -989,36 +997,42 @@ packages:
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm-musl@2.5.1':
resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-arm64-glibc@2.5.1':
resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm64-musl@2.5.1':
resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-x64-glibc@2.5.1':
resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-x64-musl@2.5.1':
resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [musl]
'@parcel/watcher-win32-arm64@2.5.1':
resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
@@ -1096,51 +1110,61 @@ packages:
resolution: {integrity: sha512-MW6N3AoC61OfE1VgnN5O1OW0gt8VTbhx9s/ZEPLBM11wEdHjeilPzOxVmmsrx5YmejpGPvez8QwGGvMU+pGxpw==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.34.3':
resolution: {integrity: sha512-2SQkhr5xvatYq0/+H6qyW0zvrQz9LM4lxGkpWURLoQX5+yP8MsERh4uWmxFohOvwCP6l/+wgiHZ1qVwLDc7Qmw==}
cpu: [arm]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.34.3':
resolution: {integrity: sha512-R3JLYt8YoRwKI5shJsovLpcR6pwIMui/MGG/MmxZ1DYI3iRSKI4qcYrvYgDf4Ss2oCR3RL3F3dYK7uAGQgMIuQ==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.34.3':
resolution: {integrity: sha512-4XQhG8v/t3S7Rxs7rmFUuM6j09hVrTArzONS3fUZ6oBRSN/ps9IPQjVhp62P0W3KhqJdQADo/MRlYRMdgxr/3w==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-loongarch64-gnu@4.34.3':
resolution: {integrity: sha512-QlW1jCUZ1LHUIYCAK2FciVw1ptHsxzApYVi05q7bz2A8oNE8QxQ85NhM4arLxkAlcnS42t4avJbSfzSQwbIaKg==}
cpu: [loong64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-powerpc64le-gnu@4.34.3':
resolution: {integrity: sha512-kMbLToizVeCcN69+nnm20Dh0hrRIAjgaaL+Wh0gWZcNt8e542d2FUGtsyuNsHVNNF3gqTJrpzUGIdwMGLEUM7g==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.34.3':
resolution: {integrity: sha512-YgD0DnZ3CHtvXRH8rzjVSxwI0kMTr0RQt3o1N92RwxGdx7YejzbBO0ELlSU48DP96u1gYYVWfUhDRyaGNqJqJg==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-s390x-gnu@4.34.3':
resolution: {integrity: sha512-dIOoOz8altjp6UjAi3U9EW99s8nta4gzi52FeI45GlPyrUH4QixUoBMH9VsVjt+9A2RiZBWyjYNHlJ/HmJOBCQ==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.34.3':
resolution: {integrity: sha512-lOyG3aF4FTKrhpzXfMmBXgeKUUXdAWmP2zSNf8HTAXPqZay6QYT26l64hVizBjq+hJx3pl0DTEyvPi9sTA6VGA==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.34.3':
resolution: {integrity: sha512-usztyYLu2i+mYzzOjqHZTaRXbUOqw3P6laNUh1zcqxbPH1P2Tz/QdJJCQSnGxCtsRQeuU2bCyraGMtMumC46rw==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rollup/rollup-win32-arm64-msvc@4.34.3':
resolution: {integrity: sha512-ojFOKaz/ZyalIrizdBq2vyc2f0kFbJahEznfZlxdB6pF9Do6++i1zS5Gy6QLf8D7/S57MHrmBLur6AeRYeQXSA==}
@@ -3732,6 +3756,11 @@ packages:
snapshots:
'@alova/adapter-xhr@2.1.1(alova@3.2.8)':
dependencies:
'@alova/shared': 1.1.2
alova: 3.2.8
'@alova/shared@1.1.2': {}
'@ampproject/remapping@2.3.0':

View File

@@ -1,47 +1,39 @@
import { request } from '@/utils'
import { http } from '@/utils'
export default {
// 创建文件/文件夹
create: (path: string, dir: boolean): any => request.post('/file/create', { path, dir }),
create: (path: string, dir: boolean): any => http.Post('/file/create', { path, dir }),
// 获取文件内容
content: (path: string): any => request.get('/file/content', { params: { path } }),
content: (path: string): any => http.Get('/file/content', { params: { path } }),
// 保存文件
save: (path: string, content: string): any => request.post('/file/save', { path, content }),
save: (path: string, content: string): any => http.Post('/file/save', { path, content }),
// 删除文件
delete: (path: string): any => request.post('/file/delete', { path }),
delete: (path: string): any => http.Post('/file/delete', { path }),
// 上传文件
upload: (path: string, formData: FormData, onProgress: any): any => {
formData.append('path', path)
return request.post('/file/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
onUploadProgress: (progressEvent: any) => {
onProgress({ percent: Math.ceil((progressEvent.loaded / progressEvent.total) * 100) })
}
})
},
upload: (formData: FormData): any => http.Post('/file/upload', formData),
// 检查文件是否存在
exist: (paths: string[]): any => request.post('/file/exist', paths),
exist: (paths: string[]): any => http.Post('/file/exist', paths),
// 移动文件
move: (paths: any[]): any => request.post('/file/move', paths),
move: (paths: any[]): any => http.Post('/file/move', paths),
// 复制文件
copy: (paths: any[]): any => request.post('/file/copy', paths),
copy: (paths: any[]): any => http.Post('/file/copy', paths),
// 远程下载
remoteDownload: (path: string, url: string): any =>
request.post('/file/remoteDownload', { path, url }),
http.Post('/file/remoteDownload', { path, url }),
// 获取文件信息
info: (path: string): any => request.get('/file/info', { params: { path } }),
info: (path: string): any => http.Get('/file/info', { params: { path } }),
// 修改文件权限
permission: (path: string, mode: string, owner: string, group: string): any =>
request.post('/file/permission', { path, mode, owner, group }),
http.Post('/file/permission', { path, mode, owner, group }),
// 压缩文件
compress: (dir: string, paths: string[], file: string): any =>
request.post('/file/compress', { dir, paths, file }),
http.Post('/file/compress', { dir, paths, file }),
// 解压文件
unCompress: (file: string, path: string): any => request.post('/file/unCompress', { file, path }),
unCompress: (file: string, path: string): any => http.Post('/file/unCompress', { file, path }),
// 搜索文件
search: (path: string, keyword: string, sub: boolean, page: number, limit: number): any =>
request.get('/file/search', { params: { path, keyword, sub, page, limit } }),
http.Get('/file/search', { params: { path, keyword, sub, page, limit } }),
// 获取文件列表
list: (path: string, page: number, limit: number, sort: string): any =>
request.get('/file/list', { params: { path, page, limit, sort } })
http.Get('/file/list', { params: { path, page, limit, sort } })
}

View File

@@ -18,25 +18,25 @@ const props = defineProps({
const disabled = ref(false) // 在出现错误的情况下禁用保存
const data = ref('')
const get = async () => {
await file
.content(props.path)
.then((res) => {
data.value = decodeBase64(res.data.content)
const get = () => {
useRequest(file.content(props.path))
.onSuccess(({ data }) => {
data.value = decodeBase64(data.content)
window.$message.success('获取成功')
})
.catch(() => {
.onError(() => {
disabled.value = true
})
}
const save = async () => {
const save = () => {
if (disabled.value) {
window.$message.error('当前状态下不可保存')
return
}
await file.save(props.path, data.value)
window.$message.success('保存成功')
useRequest(file.save(props.path, data.value)).onSuccess(() => {
window.$message.success('保存成功')
})
}
onMounted(() => {

View File

@@ -1,6 +1,7 @@
import { resolveResError } from '@/utils/http/helpers'
import type { AlovaXHRResponse } from '@alova/adapter-xhr'
import { xhrRequestAdapter } from '@alova/adapter-xhr'
import { createAlova, Method } from 'alova'
import adapterFetch from 'alova/fetch'
import VueHook from 'alova/vue'
import axios from 'axios'
import { reqReject, reqResolve, resReject, resResolve } from './interceptors'
@@ -27,15 +28,21 @@ export const http = createAlova({
id: 'panel',
cacheFor: null,
statesHook: VueHook,
requestAdapter: adapterFetch(),
requestAdapter: xhrRequestAdapter(),
baseURL: import.meta.env.VITE_BASE_API,
responded: {
onSuccess: async (response: Response, method: Method) => {
const ct = response.headers.get('Content-Type')
const json =
ct && ct.includes('application/json')
? await response.json()
: { code: response.status, message: await response.text() }
onSuccess: async (response: AlovaXHRResponse, method: Method) => {
const ct = response.headers['Content-Type'] || response.headers['content-type']
let json
try {
if (ct && ct.includes('application/json')) {
json = typeof response.data === 'string' ? JSON.parse(response.data) : response.data
} else {
json = { code: response.status, message: response.data }
}
} catch (error) {
json = { code: response.status, message: 'JSON 解析失败' }
}
const { status, statusText } = response
const { meta } = method
if (status !== 200) {

View File

@@ -24,26 +24,24 @@ const ensureExtension = (extension: string) => {
}
}
const handleArchive = async () => {
const handleArchive = () => {
ensureExtension(format.value)
loading.value = true
const message = window.$message.loading('正在压缩中...', {
duration: 0
})
const paths = selected.value.map((item) => item.replace(path.value, '').replace(/^\//, ''))
await api
.compress(path.value, paths, file.value)
.then(() => {
window.$message.success('压缩成功')
useRequest(api.compress(path.value, paths, file.value))
.onSuccess(() => {
show.value = false
selected.value = []
window.$message.success('压缩成功')
})
.catch(() => {
window.$message.error('压缩失败')
.onComplete(() => {
message?.destroy()
loading.value = false
window.$bus.emit('file:refresh')
})
message?.destroy()
loading.value = false
window.$bus.emit('file:refresh')
}
onMounted(() => {

View File

@@ -1,5 +1,14 @@
<script setup lang="ts">
import { NButton, NEllipsis, NFlex, NInput, NPopconfirm, NPopselect, NTag } from 'naive-ui'
import {
NButton,
NDataTable,
NEllipsis,
NFlex,
NInput,
NPopconfirm,
NPopselect,
NTag
} from 'naive-ui'
import type { DataTableColumns, DropdownOption } from 'naive-ui'
import type { RowData } from 'naive-ui/es/data-table/src/interface'
@@ -19,7 +28,6 @@ import EditModal from '@/views/file/EditModal.vue'
import PreviewModal from '@/views/file/PreviewModal.vue'
import type { Marked } from '@/views/file/types'
const loading = ref(false)
const sort = ref<string>('')
const path = defineModel<string>('path', { type: String, required: true })
const selected = defineModel<any[]>('selected', { type: Array, default: () => [] })
@@ -253,9 +261,9 @@ const columns: DataTableColumns<RowData> = [
NPopconfirm,
{
onPositiveClick: () => {
file.delete(row.full).then(() => {
window.$message.success('删除成功')
useRequest(file.delete(row.full)).onComplete(() => {
window.$bus.emit('file:refresh')
window.$message.success('删除成功')
})
},
onNegativeClick: () => {}
@@ -362,47 +370,17 @@ const rowProps = (row: any) => {
}
}
const data = ref<RowData[]>([])
const { loading, data, page, total, pageSize, pageCount, refresh } = usePagination(
(page, pageSize) => file.list(path.value, page, pageSize, sort.value),
{
initialData: { total: 0, list: [] },
initialPageSize: 20,
total: (res: any) => res.total,
data: (res: any) => res.items
}
)
const pagination = reactive({
page: 1,
pageCount: 1,
pageSize: 100,
itemCount: 0,
showQuickJumper: true,
showSizePicker: true,
pageSizes: [100, 200, 500, 1000, 1500, 2000, 5000]
})
const handlePageSizeChange = (pageSize: number) => {
pagination.pageSize = pageSize
handlePageChange(1)
}
const handlePageChange = async (page: number) => {
loading.value = true
await getList(path.value, page, pagination.pageSize!).finally(() => {
loading.value = false
})
}
const handleRefresh = async () => {
loading.value = true
await getList(path.value, pagination.page, pagination.pageSize!).finally(() => {
loading.value = false
})
}
const getList = async (path: string, page: number, limit: number) => {
await file.list(path, page, limit, sort.value).then((res) => {
data.value = res.data.items
pagination.page = page
pagination.itemCount = res.data.total
pagination.pageCount = res.data.total / pagination.pageSize! + 1
})
}
const handleRename = async () => {
const handleRename = () => {
const source = path.value + '/' + renameModel.value.source
const target = path.value + '/' + renameModel.value.target
if (!checkName(renameModel.value.source) || !checkName(renameModel.value.target)) {
@@ -410,31 +388,39 @@ const handleRename = async () => {
return
}
await file.exist([target]).then(async (res) => {
if (res.data[0]) {
useRequest(file.exist([target])).onSuccess(({ data }) => {
if (data[0]) {
window.$dialog.warning({
title: '警告',
content: `存在同名项,是否强制覆盖?`,
positiveText: '覆盖',
negativeText: '取消',
onPositiveClick: async () => {
await file.move([{ source, target, force: true }])
window.$message.success(
`重命名 ${renameModel.value.source}${renameModel.value.target} 成功`
)
window.$bus.emit('file:refresh')
onPositiveClick: () => {
useRequest(file.move([{ source, target, force: true }]))
.onSuccess(() => {
window.$bus.emit('file:refresh')
window.$message.success(
`重命名 ${renameModel.value.source}${renameModel.value.target} 成功`
)
})
.onComplete(() => {
renameModal.value = false
})
}
})
} else {
await file.move([{ source, target, force: false }])
window.$message.success(
`重命名 ${renameModel.value.source}${renameModel.value.target} 成功`
)
window.$bus.emit('file:refresh')
useRequest(file.move([{ source, target, force: false }]))
.onSuccess(() => {
window.$bus.emit('file:refresh')
window.$message.success(
`重命名 ${renameModel.value.source}${renameModel.value.target} 成功`
)
})
.onComplete(() => {
renameModal.value = false
})
}
})
renameModal.value = false
}
const handleUnCompress = () => {
@@ -449,17 +435,14 @@ const handleUnCompress = () => {
const message = window.$message.loading('正在解压中...', {
duration: 0
})
file
.unCompress(unCompressModel.value.file, unCompressModel.value.path)
.then(() => {
message?.destroy()
window.$message.success('解压成功')
useRequest(file.unCompress(unCompressModel.value.file, unCompressModel.value.path))
.onSuccess(() => {
unCompressModal.value = false
window.$bus.emit('file:refresh')
window.$message.success('解压成功')
})
.catch(() => {
.onComplete(() => {
message?.destroy()
window.$message.error('解压失败')
})
}
@@ -467,7 +450,7 @@ const onChecked = (rowKeys: any) => {
selected.value = rowKeys
}
const handlePaste = async () => {
const handlePaste = () => {
if (!marked.value.length) {
window.$message.error('请先标记需要复制或移动的文件/文件夹')
return
@@ -484,9 +467,9 @@ const handlePaste = async () => {
}
})
const sources = paths.map((item: any) => item.target)
await file.exist(sources).then(async (res) => {
for (let i = 0; i < res.data.length; i++) {
if (res.data[i]) {
useRequest(file.exist(sources)).onSuccess(({ data }) => {
for (let i = 0; i < data.length; i++) {
if (data[i]) {
flag = true
paths[i].force = true
}
@@ -501,13 +484,13 @@ const handlePaste = async () => {
.join(', ')} 是否覆盖?`,
positiveText: '覆盖',
negativeText: '取消',
onPositiveClick: async () => {
onPositiveClick: () => {
if (markedType.value == 'copy') {
await file.copy(paths).then(() => {
useRequest(file.copy(paths)).onSuccess(() => {
window.$message.success('复制成功')
})
} else {
await file.move(paths).then(() => {
useRequest(file.move(paths)).onSuccess(() => {
window.$message.success('移动成功')
})
}
@@ -521,11 +504,11 @@ const handlePaste = async () => {
})
} else {
if (markedType.value == 'copy') {
await file.copy(paths).then(() => {
useRequest(file.copy(paths)).onSuccess(() => {
window.$message.success('复制成功')
})
} else {
await file.move(paths).then(() => {
useRequest(file.move(paths)).onSuccess(() => {
window.$message.success('移动成功')
})
}
@@ -595,9 +578,9 @@ const handleSelect = (key: string) => {
renameModal.value = true
break
case 'delete':
file.delete(selectedRow.value.full).then(() => {
window.$message.success('删除成功')
useRequest(file.delete(selectedRow.value.full)).onSuccess(() => {
window.$bus.emit('file:refresh')
window.$message.success('删除成功')
})
break
}
@@ -618,15 +601,15 @@ const handleSorterChange = (sorter: {
switch (sorter.order) {
case 'ascend':
sort.value = 'asc'
handleRefresh()
refresh()
break
case 'descend':
sort.value = 'desc'
handleRefresh()
refresh()
break
default:
sort.value = ''
handleRefresh()
refresh()
break
}
}
@@ -638,12 +621,12 @@ onMounted(() => {
path,
() => {
selected.value = []
handlePageChange(1)
refresh()
window.$bus.emit('push-history', path.value)
},
{ immediate: true }
)
window.$bus.on('file:refresh', handleRefresh)
window.$bus.on('file:refresh', refresh)
})
onUnmounted(() => {
@@ -662,14 +645,22 @@ onUnmounted(() => {
:data="data"
:row-props="rowProps"
:loading="loading"
:pagination="pagination"
:row-key="(row: any) => row.full"
:checked-row-keys="selected"
max-height="60vh"
@update:page="handlePageChange"
@update:page-size="handlePageSizeChange"
@update:sorter="handleSorterChange"
@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: [100, 200, 500, 1000, 1500, 2000, 5000]
}"
/>
<n-dropdown
placement="bottom-start"

View File

@@ -16,11 +16,14 @@ const checkbox = ref({
})
const handlePermission = async () => {
for (const path of selected.value) {
await file.permission(path, `0${mode.value}`, owner.value, group.value).then(() => {
const promises = selected.value.map((path) =>
useRequest(file.permission(path, `0${mode.value}`, owner.value, group.value)).onSuccess(() => {
window.$message.success(`修改 ${path} 成功`)
})
}
)
await Promise.all(promises)
show.value = false
selected.value = []
window.$bus.emit('file:refresh')

View File

@@ -14,9 +14,9 @@ watch(
() => path.value,
() => {
content.value = ''
file.content(path.value).then((res) => {
mime.value = res.data.mime
content.value = res.data.content
useRequest(file.content(path.value)).onSuccess(({ data }) => {
mime.value = data.mime
content.value = data.content
})
}
)

View File

@@ -72,9 +72,9 @@ const columns: DataTableColumns<RowData> = [
NPopconfirm,
{
onPositiveClick: () => {
file.delete(row.full).then(() => {
window.$message.success('删除成功')
useRequest(file.delete(row.full)).onSuccess(() => {
window.$bus.emit('file:refresh')
window.$message.success('删除成功')
})
},
onNegativeClick: () => {}
@@ -126,12 +126,11 @@ const handlePageChange = (page: number) => {
const search = async (page: number) => {
loading.value = true
await file
.search(path.value, keyword.value, sub.value, page, pagination.pageSize!)
.then((res) => {
data.value = res.data.items
pagination.itemCount = res.data.total
pagination.pageCount = res.data.total / pagination.pageSize! + 1
useRequest(file.search(path.value, keyword.value, sub.value, page, pagination.pageSize!))
.then(({ data }) => {
data.value = data.items
pagination.itemCount = data.total
pagination.pageCount = data.total / pagination.pageSize! + 1
})
.catch(() => {
window.$message.error('搜索失败')

View File

@@ -36,10 +36,10 @@ const handleCreate = () => {
}
const fullPath = path.value + '/' + createModel.value.path
file.create(fullPath, createModel.value.dir).then(() => {
useRequest(file.create(fullPath, createModel.value.dir)).onSuccess(() => {
create.value = false
window.$message.success('创建成功')
window.$bus.emit('file:refresh')
window.$message.success('创建成功')
})
}
@@ -49,13 +49,13 @@ const handleDownload = () => {
return
}
file
.remoteDownload(path.value + '/' + downloadModel.value.path, downloadModel.value.url)
.then(() => {
download.value = false
window.$message.success('下载任务创建成功')
window.$bus.emit('file:refresh')
})
useRequest(
file.remoteDownload(path.value + '/' + downloadModel.value.path, downloadModel.value.url)
).onSuccess(() => {
download.value = false
window.$bus.emit('file:refresh')
window.$message.success('下载任务创建成功')
})
}
const handleCopy = () => {
@@ -92,7 +92,7 @@ const handleCancel = () => {
marked.value = []
}
const handlePaste = async () => {
const handlePaste = () => {
if (!marked.value.length) {
window.$message.error('请先标记需要复制或移动的文件/文件夹')
return
@@ -109,9 +109,9 @@ const handlePaste = async () => {
}
})
const sources = paths.map((item: any) => item.target)
await file.exist(sources).then(async (res) => {
for (let i = 0; i < res.data.length; i++) {
if (res.data[i]) {
useRequest(file.exist(sources)).onSuccess(({ data }) => {
for (let i = 0; i < data.length; i++) {
if (data[i]) {
flag = true
paths[i].force = true
}
@@ -128,16 +128,18 @@ const handlePaste = async () => {
negativeText: '取消',
onPositiveClick: async () => {
if (markedType.value == 'copy') {
await file.copy(paths).then(() => {
useRequest(file.copy(paths)).onSuccess(() => {
marked.value = []
window.$bus.emit('file:refresh')
window.$message.success('复制成功')
})
} else {
await file.move(paths).then(() => {
useRequest(file.move(paths)).onSuccess(() => {
marked.value = []
window.$bus.emit('file:refresh')
window.$message.success('移动成功')
})
}
marked.value = []
window.$bus.emit('file:refresh')
},
onNegativeClick: () => {
marked.value = []
@@ -146,16 +148,18 @@ const handlePaste = async () => {
})
} else {
if (markedType.value == 'copy') {
await file.copy(paths).then(() => {
useRequest(file.copy(paths)).onSuccess(() => {
marked.value = []
window.$bus.emit('file:refresh')
window.$message.success('复制成功')
})
} else {
await file.move(paths).then(() => {
useRequest(file.move(paths)).onSuccess(() => {
marked.value = []
window.$bus.emit('file:refresh')
window.$message.success('移动成功')
})
}
marked.value = []
window.$bus.emit('file:refresh')
}
})
}
@@ -166,14 +170,16 @@ const bulkDelete = async () => {
return
}
for (const path of selected.value) {
await file.delete(path).then(() => {
const promises = selected.value.map((path) =>
useRequest(file.delete(path)).onSuccess(() => {
window.$message.success(`删除 ${path} 成功`)
window.$bus.emit('file:refresh')
})
}
)
await Promise.all(promises)
selected.value = []
window.$bus.emit('file:refresh')
}
// 自动填充下载文件名

View File

@@ -9,17 +9,23 @@ const upload = ref<any>(null)
const uploadRequest = ({ file, onFinish, onError, onProgress }: UploadCustomRequestOptions) => {
const formData = new FormData()
formData.append('path', `${path.value}/${file.name}`)
formData.append('file', file.file as File)
api
.upload(`${path.value}/${file.name}`, formData, onProgress)
.then(() => {
window.$message.success(`上传 ${file.name} 成功`)
window.$bus.emit('file:refresh')
const { uploading } = useRequest(api.upload(formData))
.onSuccess(() => {
onFinish()
window.$bus.emit('file:refresh')
window.$message.success(`上传 ${file.name} 成功`)
})
.catch(() => {
.onError(() => {
onError()
})
.onComplete(() => {
stopWatch()
})
const stopWatch = watch(uploading, (progress) => {
onProgress({ percent: Math.ceil((progress.loaded / progress.total) * 100) })
})
}
</script>
@@ -34,7 +40,6 @@ const uploadRequest = ({ file, onFinish, onError, onProgress }: UploadCustomRequ
:segmented="false"
>
<n-flex vertical>
<n-alert type="info">若上传报网络错误请开启面板 HTTPS 后重试</n-alert>
<n-upload
ref="upload"
multiple
@@ -47,7 +52,7 @@ const uploadRequest = ({ file, onFinish, onError, onProgress }: UploadCustomRequ
<the-icon :size="48" icon="bi:arrow-up-square" />
</div>
<NText text-18> 点击或者拖动文件到该区域来上传</NText>
<NP depth="3" m-10> 大文件建议使用 SFTP 上传 </NP>
<NP depth="3" m-10> 大文件建议使用 SFTP 等方式上传 </NP>
</n-upload-dragger>
</n-upload>
</n-flex>

View File

@@ -131,21 +131,21 @@ const handleDelete = (row: any) => {
})
}
const batchDelete = () => {
const batchDelete = async () => {
if (selectedRowKeys.value.length === 0) {
window.$message.info('请选择要删除的规则')
return
}
for (const key of selectedRowKeys.value) {
// 解析json
const promises = selectedRowKeys.value.map((key: any) => {
const rule = JSON.parse(key)
useRequest(firewall.deleteForward(rule)).onSuccess(() => {
return useRequest(firewall.deleteForward(rule)).then(() => {
window.$message.success(`${rule.protocol} ${rule.target_ip}:${rule.target_port} 删除成功`)
})
}
})
refresh()
await Promise.all(promises)
await refresh()
}
const onChecked = (rowKeys: any) => {

View File

@@ -173,21 +173,21 @@ const handleDelete = (row: any) => {
})
}
const batchDelete = () => {
const batchDelete = async () => {
if (selectedRowKeys.value.length === 0) {
window.$message.info('请选择要删除的规则')
return
}
for (const key of selectedRowKeys.value) {
// 解析json
const promises = selectedRowKeys.value.map((key: any) => {
const rule = JSON.parse(key)
useRequest(firewall.deleteIpRule(rule)).onSuccess(() => {
return useRequest(firewall.deleteIpRule(rule)).then(() => {
window.$message.success(`${rule.address} 删除成功`)
})
}
})
refresh()
await Promise.all(promises)
await refresh()
}
const onChecked = (rowKeys: any) => {

View File

@@ -210,23 +210,23 @@ const handleDelete = async (row: any) => {
})
}
const batchDelete = () => {
const batchDelete = async () => {
if (selectedRowKeys.value.length === 0) {
window.$message.info('请选择要删除的规则')
return
}
for (const key of selectedRowKeys.value) {
// 解析json
const promises = selectedRowKeys.value.map((key: any) => {
const rule = JSON.parse(key)
useRequest(firewall.deleteRule(rule)).onSuccess(() => {
return useRequest(firewall.deleteRule(rule)).then(() => {
const port =
rule.port_start == rule.port_end ? rule.port_start : `${rule.port_start}-${rule.port_end}`
window.$message.success(`${rule.family} 规则 ${port}/${rule.protocol} 删除成功`)
})
}
})
refresh()
await Promise.all(promises)
await refresh()
}
const onChecked = (rowKeys: any) => {

View File

@@ -307,19 +307,21 @@ const handleCreate = async () => {
})
}
const batchDelete = async () => {
const bulkDelete = async () => {
if (selectedRowKeys.value.length === 0) {
window.$message.info('请选择要删除的网站')
return
}
for (const id of selectedRowKeys.value) {
useRequest(website.delete(id, true, false)).onSuccess(() => {
refresh()
const site = data.value.find((item: any) => item.id === id)
const promises = selectedRowKeys.value.map((id: any) => {
const site = data.value.find((item: any) => item.id === id)
return useRequest(website.delete(id, true, false)).then(() => {
window.$message.success('网站 ' + site?.name + ' 删除成功')
})
}
})
await Promise.all(promises)
await refresh()
}
const formatDbValue = (value: string) => {
@@ -346,7 +348,7 @@ onMounted(() => {
<n-button type="primary" @click="createModal = true">
{{ $t('websiteIndex.create.trigger') }}
</n-button>
<n-popconfirm @positive-click="batchDelete">
<n-popconfirm @positive-click="bulkDelete">
<template #trigger>
<n-button type="error"> 批量删除 </n-button>
</template>