mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 07:57:21 +08:00
feat: 优化菜单排序
This commit is contained in:
@@ -1,251 +1,23 @@
|
||||
<script setup lang="ts">
|
||||
<script lang="ts" setup>
|
||||
defineOptions({
|
||||
name: 'app-index'
|
||||
})
|
||||
|
||||
import VersionModal from '@/views/app/VersionModal.vue'
|
||||
import InstallView from '@/views/app/InstallView.vue'
|
||||
|
||||
import { NButton, NDataTable, NFlex, NPopconfirm, NSwitch } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import app from '@/api/panel/app'
|
||||
import TheIcon from '@/components/custom/TheIcon.vue'
|
||||
import { router } from '@/router'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
|
||||
const versionModalShow = ref(false)
|
||||
const versionModalOperation = ref($gettext('Install'))
|
||||
const versionModalInfo = ref<any>({})
|
||||
|
||||
const columns: any = [
|
||||
{
|
||||
key: 'icon',
|
||||
fixed: 'left',
|
||||
width: 80,
|
||||
align: 'center',
|
||||
render(row: any) {
|
||||
return h(TheIcon, {
|
||||
icon: row.icon,
|
||||
size: 26
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
title: $gettext('App Name'),
|
||||
key: 'name',
|
||||
width: 200,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: $gettext('Description'),
|
||||
key: 'description',
|
||||
minWidth: 300,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: $gettext('Installed Version'),
|
||||
key: 'installed_version',
|
||||
width: 160,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: $gettext('Show in Home'),
|
||||
key: 'show',
|
||||
width: 140,
|
||||
render(row: any) {
|
||||
return h(NSwitch, {
|
||||
size: 'small',
|
||||
rubberBand: false,
|
||||
value: row.show,
|
||||
onUpdateValue: () => handleShowChange(row)
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
title: $gettext('Actions'),
|
||||
key: 'actions',
|
||||
width: 350,
|
||||
hideInExcel: true,
|
||||
render(row: any) {
|
||||
return h(NFlex, null, {
|
||||
default: () => [
|
||||
row.installed && row.update_exist
|
||||
? h(
|
||||
NPopconfirm,
|
||||
{
|
||||
onPositiveClick: () => handleUpdate(row.slug)
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return $gettext(
|
||||
'Updating app %{ app } may reset related configurations to default state, are you sure to continue?',
|
||||
{ app: row.name }
|
||||
)
|
||||
},
|
||||
trigger: () => {
|
||||
return h(
|
||||
NButton,
|
||||
{
|
||||
size: 'small',
|
||||
type: 'warning'
|
||||
},
|
||||
{
|
||||
default: () => $gettext('Update')
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
: null,
|
||||
row.installed
|
||||
? h(
|
||||
NButton,
|
||||
{
|
||||
size: 'small',
|
||||
type: 'success',
|
||||
onClick: () => handleManage(row.slug)
|
||||
},
|
||||
{
|
||||
default: () => $gettext('Manage')
|
||||
}
|
||||
)
|
||||
: null,
|
||||
row.installed
|
||||
? h(
|
||||
NPopconfirm,
|
||||
{
|
||||
onPositiveClick: () => handleUninstall(row.slug)
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return $gettext('Are you sure to uninstall app %{ app }?', { app: row.name })
|
||||
},
|
||||
trigger: () => {
|
||||
return h(
|
||||
NButton,
|
||||
{
|
||||
size: 'small',
|
||||
type: 'error'
|
||||
},
|
||||
{
|
||||
default: () => $gettext('Uninstall')
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
: null,
|
||||
!row.installed
|
||||
? h(
|
||||
NButton,
|
||||
{
|
||||
size: 'small',
|
||||
type: 'info',
|
||||
onClick: () => {
|
||||
versionModalShow.value = true
|
||||
versionModalOperation.value = $gettext('Install')
|
||||
versionModalInfo.value = row
|
||||
}
|
||||
},
|
||||
{
|
||||
default: () => $gettext('Install')
|
||||
}
|
||||
)
|
||||
: null
|
||||
]
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const { loading, data, page, total, pageSize, pageCount, refresh } = usePagination(
|
||||
(page, pageSize) => app.list(page, pageSize),
|
||||
{
|
||||
initialData: { total: 0, list: [] },
|
||||
initialPageSize: 20,
|
||||
total: (res: any) => res.total,
|
||||
data: (res: any) => res.items
|
||||
}
|
||||
)
|
||||
|
||||
const handleShowChange = (row: any) => {
|
||||
useRequest(app.updateShow(row.slug, !row.show)).onSuccess(() => {
|
||||
row.show = !row.show
|
||||
window.$message.success($gettext('Setup successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleUpdate = (slug: string) => {
|
||||
useRequest(app.update(slug)).onSuccess(() => {
|
||||
window.$message.success(
|
||||
$gettext('Task submitted, please check the progress in background tasks')
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const handleUninstall = (slug: string) => {
|
||||
useRequest(app.uninstall(slug)).onSuccess(() => {
|
||||
window.$message.success(
|
||||
$gettext('Task submitted, please check the progress in background tasks')
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const handleManage = (slug: string) => {
|
||||
router.push({ name: 'apps-' + slug + '-index' })
|
||||
}
|
||||
|
||||
const handleUpdateCache = () => {
|
||||
useRequest(app.updateCache()).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success($gettext('Cache updated successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
refresh()
|
||||
})
|
||||
const currentTab = ref('installed')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<common-page show-footer>
|
||||
<n-flex vertical>
|
||||
<n-flex>
|
||||
<n-button type="primary" @click="handleUpdateCache">
|
||||
{{ $gettext('Update Cache') }}
|
||||
</n-button>
|
||||
</n-flex>
|
||||
<n-alert type="warning">{{
|
||||
$gettext(
|
||||
'Before updating apps, it is strongly recommended to backup/snapshot first, so you can roll back immediately if there are any issues!'
|
||||
)
|
||||
}}</n-alert>
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
:scroll-x="1200"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:row-key="(row: any) => row.slug"
|
||||
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-flex>
|
||||
<version-modal
|
||||
v-model:show="versionModalShow"
|
||||
v-model:operation="versionModalOperation"
|
||||
v-model:info="versionModalInfo"
|
||||
/>
|
||||
<common-page show-header show-footer>
|
||||
<template #tabbar>
|
||||
<n-tabs v-model:value="currentTab" animated>
|
||||
<n-tab name="installed" :tab="$gettext('Installed')" />
|
||||
<n-tab name="install" :tab="$gettext('Install')" />
|
||||
<n-tab name="environment" :tab="$gettext('Environment')" />
|
||||
<n-tab name="compose" :tab="$gettext('Compose Templates')" />
|
||||
</n-tabs>
|
||||
</template>
|
||||
<install-view v-if="currentTab === 'install'" />
|
||||
</common-page>
|
||||
</template>
|
||||
|
||||
249
web/src/views/app/InstallView.vue
Normal file
249
web/src/views/app/InstallView.vue
Normal file
@@ -0,0 +1,249 @@
|
||||
<script setup lang="ts">
|
||||
defineOptions({
|
||||
name: 'app-index'
|
||||
})
|
||||
|
||||
import VersionModal from '@/views/app/VersionModal.vue'
|
||||
|
||||
import { NButton, NDataTable, NFlex, NPopconfirm, NSwitch } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import app from '@/api/panel/app'
|
||||
import TheIcon from '@/components/custom/TheIcon.vue'
|
||||
import { router } from '@/router'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
|
||||
const versionModalShow = ref(false)
|
||||
const versionModalOperation = ref($gettext('Install'))
|
||||
const versionModalInfo = ref<any>({})
|
||||
|
||||
const columns: any = [
|
||||
{
|
||||
key: 'icon',
|
||||
fixed: 'left',
|
||||
width: 80,
|
||||
align: 'center',
|
||||
render(row: any) {
|
||||
return h(TheIcon, {
|
||||
icon: row.icon,
|
||||
size: 26
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
title: $gettext('App Name'),
|
||||
key: 'name',
|
||||
width: 200,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: $gettext('Description'),
|
||||
key: 'description',
|
||||
minWidth: 300,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: $gettext('Installed Version'),
|
||||
key: 'installed_version',
|
||||
width: 160,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: $gettext('Show in Home'),
|
||||
key: 'show',
|
||||
width: 140,
|
||||
render(row: any) {
|
||||
return h(NSwitch, {
|
||||
size: 'small',
|
||||
rubberBand: false,
|
||||
value: row.show,
|
||||
onUpdateValue: () => handleShowChange(row)
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
title: $gettext('Actions'),
|
||||
key: 'actions',
|
||||
width: 350,
|
||||
hideInExcel: true,
|
||||
render(row: any) {
|
||||
return h(NFlex, null, {
|
||||
default: () => [
|
||||
row.installed && row.update_exist
|
||||
? h(
|
||||
NPopconfirm,
|
||||
{
|
||||
onPositiveClick: () => handleUpdate(row.slug)
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return $gettext(
|
||||
'Updating app %{ app } may reset related configurations to default state, are you sure to continue?',
|
||||
{ app: row.name }
|
||||
)
|
||||
},
|
||||
trigger: () => {
|
||||
return h(
|
||||
NButton,
|
||||
{
|
||||
size: 'small',
|
||||
type: 'warning'
|
||||
},
|
||||
{
|
||||
default: () => $gettext('Update')
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
: null,
|
||||
row.installed
|
||||
? h(
|
||||
NButton,
|
||||
{
|
||||
size: 'small',
|
||||
type: 'success',
|
||||
onClick: () => handleManage(row.slug)
|
||||
},
|
||||
{
|
||||
default: () => $gettext('Manage')
|
||||
}
|
||||
)
|
||||
: null,
|
||||
row.installed
|
||||
? h(
|
||||
NPopconfirm,
|
||||
{
|
||||
onPositiveClick: () => handleUninstall(row.slug)
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return $gettext('Are you sure to uninstall app %{ app }?', { app: row.name })
|
||||
},
|
||||
trigger: () => {
|
||||
return h(
|
||||
NButton,
|
||||
{
|
||||
size: 'small',
|
||||
type: 'error'
|
||||
},
|
||||
{
|
||||
default: () => $gettext('Uninstall')
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
: null,
|
||||
!row.installed
|
||||
? h(
|
||||
NButton,
|
||||
{
|
||||
size: 'small',
|
||||
type: 'info',
|
||||
onClick: () => {
|
||||
versionModalShow.value = true
|
||||
versionModalOperation.value = $gettext('Install')
|
||||
versionModalInfo.value = row
|
||||
}
|
||||
},
|
||||
{
|
||||
default: () => $gettext('Install')
|
||||
}
|
||||
)
|
||||
: null
|
||||
]
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const { loading, data, page, total, pageSize, pageCount, refresh } = usePagination(
|
||||
(page, pageSize) => app.list(page, pageSize),
|
||||
{
|
||||
initialData: { total: 0, list: [] },
|
||||
initialPageSize: 20,
|
||||
total: (res: any) => res.total,
|
||||
data: (res: any) => res.items
|
||||
}
|
||||
)
|
||||
|
||||
const handleShowChange = (row: any) => {
|
||||
useRequest(app.updateShow(row.slug, !row.show)).onSuccess(() => {
|
||||
row.show = !row.show
|
||||
window.$message.success($gettext('Setup successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleUpdate = (slug: string) => {
|
||||
useRequest(app.update(slug)).onSuccess(() => {
|
||||
window.$message.success(
|
||||
$gettext('Task submitted, please check the progress in background tasks')
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const handleUninstall = (slug: string) => {
|
||||
useRequest(app.uninstall(slug)).onSuccess(() => {
|
||||
window.$message.success(
|
||||
$gettext('Task submitted, please check the progress in background tasks')
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const handleManage = (slug: string) => {
|
||||
router.push({ name: 'apps-' + slug + '-index' })
|
||||
}
|
||||
|
||||
const handleUpdateCache = () => {
|
||||
useRequest(app.updateCache()).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success($gettext('Cache updated successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
refresh()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-flex vertical>
|
||||
<n-flex>
|
||||
<n-button type="primary" @click="handleUpdateCache">
|
||||
{{ $gettext('Update Cache') }}
|
||||
</n-button>
|
||||
</n-flex>
|
||||
<n-alert type="warning">{{
|
||||
$gettext(
|
||||
'Before updating apps, it is strongly recommended to backup/snapshot first, so you can roll back immediately if there are any issues!'
|
||||
)
|
||||
}}</n-alert>
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
:scroll-x="1200"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:row-key="(row: any) => row.slug"
|
||||
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-flex>
|
||||
<version-modal
|
||||
v-model:show="versionModalShow"
|
||||
v-model:operation="versionModalOperation"
|
||||
v-model:info="versionModalInfo"
|
||||
/>
|
||||
</template>
|
||||
@@ -7,7 +7,7 @@ export default {
|
||||
path: '/app',
|
||||
component: Layout,
|
||||
meta: {
|
||||
order: 90
|
||||
order: 1
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
||||
@@ -93,9 +93,9 @@ onUnmounted(() => {
|
||||
<common-page show-header show-footer>
|
||||
<template #tabbar>
|
||||
<n-tabs v-model:value="currentTab" animated>
|
||||
<n-tab name="cert" :tab="$gettext('Certificate List')" />
|
||||
<n-tab name="account" :tab="$gettext('Account List')" />
|
||||
<n-tab name="dns" :tab="$gettext('DNS List')" />
|
||||
<n-tab name="cert" :tab="$gettext('Certificate')" />
|
||||
<n-tab name="account" :tab="$gettext('Account')" />
|
||||
<n-tab name="dns" :tab="$gettext('DNS')" />
|
||||
</n-tabs>
|
||||
</template>
|
||||
<n-flex vertical>
|
||||
|
||||
@@ -7,7 +7,7 @@ export default {
|
||||
path: '/container',
|
||||
component: Layout,
|
||||
meta: {
|
||||
order: 40
|
||||
order: 20
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ export default {
|
||||
path: '/database',
|
||||
component: Layout,
|
||||
meta: {
|
||||
order: 2
|
||||
order: 4
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ export default {
|
||||
path: '/firewall',
|
||||
component: Layout,
|
||||
meta: {
|
||||
order: 30
|
||||
order: 40
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ export default {
|
||||
path: '/monitor',
|
||||
component: Layout,
|
||||
meta: {
|
||||
order: 20
|
||||
order: 30
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
||||
21
web/src/views/project/IndexView.vue
Normal file
21
web/src/views/project/IndexView.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<script lang="ts" setup>
|
||||
defineOptions({
|
||||
name: 'project-index'
|
||||
})
|
||||
|
||||
const currentTab = ref('general')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<common-page show-header show-footer>
|
||||
<template #tabbar>
|
||||
<n-tabs v-model:value="currentTab" animated>
|
||||
<n-tab name="general" :tab="$gettext('General')" />
|
||||
<n-tab name="php" :tab="$gettext('PHP')" />
|
||||
<n-tab name="java" :tab="$gettext('Java')" />
|
||||
<n-tab name="python" :tab="$gettext('Python')" />
|
||||
<n-tab name="nodejs" :tab="$gettext('Node.js')" />
|
||||
</n-tabs>
|
||||
</template>
|
||||
</common-page>
|
||||
</template>
|
||||
25
web/src/views/project/route.ts
Normal file
25
web/src/views/project/route.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import type { RouteType } from '~/types/router'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
|
||||
export default {
|
||||
name: 'project',
|
||||
path: '/project',
|
||||
component: Layout,
|
||||
meta: {
|
||||
order: 3
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'project-index',
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: 'Projects',
|
||||
icon: 'mdi:folder-multiple',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteType
|
||||
@@ -7,7 +7,7 @@ export default {
|
||||
path: '/website',
|
||||
component: Layout,
|
||||
meta: {
|
||||
order: 1
|
||||
order: 2
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user