2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 09:13:49 +08:00
Files
panel/web/src/views/firewall/ForwardView.vue
2025-08-23 03:18:04 +08:00

200 lines
4.4 KiB
Vue

<script setup lang="ts">
import { NButton, NDataTable, NPopconfirm, NTag } from 'naive-ui'
import { useGettext } from 'vue3-gettext'
import firewall from '@/api/panel/firewall'
import CreateForwardModal from '@/views/firewall/CreateForwardModal.vue'
const { $gettext } = useGettext()
const createModalShow = ref(false)
const columns: any = [
{ type: 'selection', fixed: 'left' },
{
title: $gettext('Transport Protocol'),
key: 'protocol',
width: 150,
resizable: true,
ellipsis: { tooltip: true },
render(row: any): any {
return h(NTag, null, {
default: () => {
if (row.protocol !== '') {
return row.protocol
}
return $gettext('None')
}
})
}
},
{
title: $gettext('Port'),
key: 'port',
width: 150,
render(row: any): any {
return h(NTag, null, {
default: () => {
return row.port
}
})
}
},
{
title: $gettext('Target IP'),
key: 'target_ip',
minWidth: 200,
render(row: any): any {
return h(
NTag,
{
type: 'info'
},
{
default: () => {
return row.target_ip
}
}
)
}
},
{
title: $gettext('Target Port'),
key: 'target_port',
width: 150,
render(row: any): any {
return h(
NTag,
{
type: 'info'
},
{
default: () => {
return row.target_port
}
}
)
}
},
{
title: $gettext('Actions'),
key: 'actions',
width: 200,
hideInExcel: true,
render(row: any) {
return [
h(
NPopconfirm,
{
onPositiveClick: () => handleDelete(row)
},
{
default: () => {
return $gettext('Are you sure you want to delete?')
},
trigger: () => {
return h(
NButton,
{
size: 'small',
type: 'error',
style: 'margin-left: 15px;'
},
{
default: () => $gettext('Delete')
}
)
}
}
)
]
}
}
]
const { loading, data, page, total, pageSize, pageCount, refresh } = usePagination(
(page, pageSize) => firewall.forwards(page, pageSize),
{
initialData: { total: 0, list: [] },
initialPageSize: 20,
total: (res: any) => res.total,
data: (res: any) => res.items
}
)
const selectedRowKeys = ref<any>([])
const handleDelete = (row: any) => {
useRequest(firewall.deleteForward(row)).onSuccess(() => {
refresh()
window.$message.success($gettext('Deleted successfully'))
})
}
const batchDelete = async () => {
if (selectedRowKeys.value.length === 0) {
window.$message.info($gettext('Please select rules to delete'))
return
}
const promises = selectedRowKeys.value.map((key: any) => {
const rule = JSON.parse(key)
return firewall.deleteForward(rule)
})
await Promise.all(promises)
selectedRowKeys.value = []
refresh()
window.$message.success($gettext('Deleted successfully'))
}
watch(createModalShow, () => {
refresh()
})
onMounted(() => {
refresh()
})
</script>
<template>
<n-flex vertical :size="20">
<n-flex items-center>
<n-button type="primary" @click="createModalShow = true">
{{ $gettext('Create Forwarding') }}
</n-button>
<n-popconfirm @positive-click="batchDelete">
<template #trigger>
<n-button type="warning">
{{ $gettext('Batch Delete') }}
</n-button>
</template>
{{ $gettext('Are you sure you want to batch delete?') }}
</n-popconfirm>
</n-flex>
<n-data-table
striped
remote
:scroll-x="1000"
:loading="loading"
:columns="columns"
:data="data"
:row-key="(row: any) => JSON.stringify(row)"
v-model:checked-row-keys="selectedRowKeys"
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>
<create-forward-modal v-model:show="createModalShow" />
</template>
<style scoped lang="scss"></style>